Compare commits

...

1413 Commits

Author SHA1 Message Date
Dan Finneran
296c9c1580 Unintentionally created duplicate functions that can't be used
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-08-12 12:17:20 +00:00
Daniel Finneran
d8877072d4 Merge pull request #1219 from kube-vip/v1-release
Version ONE DOT ZERO
2025-07-31 16:42:23 +01:00
Dan Finneran
89a8dc7de1 default setting to 0
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-31 16:09:10 +02:00
Dan Finneran
704c346f5e naming convention lint fix
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-31 16:09:10 +02:00
Dan Finneran
65061c5cd9 Adds an annotation to set the return path filter for a macvlan nic
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-31 16:09:10 +02:00
Daniel Finneran
32233918b4 Version ONE DOT ZERO 2025-07-31 12:34:37 +01:00
Daniel Finneran
76169da60f Merge pull request #1216 from kube-vip/dependabot/go_modules/github.com/docker/docker-28.3.3incompatible
Bump github.com/docker/docker from 28.3.0+incompatible to 28.3.3+incompatible
2025-07-31 12:33:44 +01:00
Daniel Finneran
9bcf1413f0 Merge pull request #1211 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.20.4
Bump anchore/sbom-action from 0.20.1 to 0.20.4
2025-07-31 12:33:28 +01:00
Daniel Finneran
8e428e875f Merge pull request #1203 from kube-vip/dependabot/docker/alpine-3.22.1
Bump alpine from 3.22.0 to 3.22.1
2025-07-31 12:33:14 +01:00
dependabot[bot]
2fbecc25e5 Bump alpine from 3.22.0 to 3.22.1
Bumps alpine from 3.22.0 to 3.22.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-30 15:17:21 +00:00
Daniel Finneran
02e77271d0 Merge pull request #1202 from kube-vip/dependabot/docker/golang-1.24.5-alpine3.22 2025-07-30 16:16:18 +01:00
Daniel Finneran
3d61888e58 Merge pull request #1192 from kube-vip/dependabot/go_modules/sigs.k8s.io/kind-0.29.0 2025-07-30 16:15:52 +01:00
dependabot[bot]
efe75f491b Bump sigs.k8s.io/kind from 0.27.0 to 0.29.0
Bumps [sigs.k8s.io/kind](https://github.com/kubernetes-sigs/kind) from 0.27.0 to 0.29.0.
- [Release notes](https://github.com/kubernetes-sigs/kind/releases)
- [Commits](https://github.com/kubernetes-sigs/kind/compare/v0.27.0...v0.29.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/kind
  dependency-version: 0.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-30 13:55:46 +00:00
Daniel Finneran
000c139004 Merge pull request #1194 from kube-vip/dependabot/go_modules/github.com/vishvananda/netlink-1.3.1 2025-07-30 14:50:38 +01:00
Daniel Finneran
c39b84f0a9 Merge pull request #1193 from kube-vip/dependabot/go_modules/github.com/osrg/gobgp/v3-3.37.0 2025-07-30 14:50:25 +01:00
dependabot[bot]
ee958addaa Bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 28.3.0+incompatible to 28.3.3+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.0...v28.3.3)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-version: 28.3.3+incompatible
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-30 13:48:44 +00:00
Daniel Finneran
8fe53351f8 Merge pull request #1215 from kube-vip/endpointslice 2025-07-30 14:47:26 +01:00
Daniel Finneran
bc9d860d83 Merge pull request #1213 from kube-vip/egress_internal 2025-07-30 14:47:07 +01:00
Dan Finneran
332a23e543 Bump k8s api and endpointslices as default
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-29 13:36:32 +00:00
Dan Finneran
b20713b50f linting issue with port out of bounds.
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-28 16:18:47 +00:00
Dan Finneran
94e96581ef typo and add SCTP
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-28 16:13:20 +00:00
Dan Finneran
61be6d0b6a fighting with merge conflicts
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-28 16:08:53 +00:00
Dan Finneran
be22805a7d sigh
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-28 16:08:22 +00:00
Dan Finneran
25f6253286 Adds the internal egress functionality
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-28 16:01:00 +00:00
dependabot[bot]
f3e9fb6ea9 Bump github.com/osrg/gobgp/v3 from 3.36.0 to 3.37.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.36.0 to 3.37.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.36.0...v3.37.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-version: 3.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-28 15:17:29 +00:00
Patryk Strusiewicz-Surmacki
0f3dda02c4 Refactoring services-watcher code
Co-authored-by: Cellebyte <marcel.fest@live.de>
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-28 17:14:09 +02:00
Dan Finneran
a2873b5465 Adds the internal egress functionality
Signed-off-by: Dan Finneran <dan@thebsdbox.co.uk>
2025-07-28 13:57:50 +00:00
dependabot[bot]
202d45e5ab Bump anchore/sbom-action from 0.20.1 to 0.20.4
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.20.1 to 0.20.4.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.20.1...v0.20.4)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-28 03:11:16 +00:00
Daniel Finneran
f5e4612c03 Merge pull request #1210 from kube-vip/fix/ci 2025-07-27 22:14:39 +01:00
Cellebyte
de888c501c split ci into two files
Signed-off-by: Cellebyte <marcel.fest@live.de>
2025-07-27 23:02:09 +02:00
Cellebyte
47bc83c248 Don't execute the e2e-tests in parallel
Signed-off-by: Cellebyte <marcel.fest@live.de>
2025-07-27 23:02:09 +02:00
Patryk Strusiewicz-Surmacki
1cf637c569 Moved endpoint-related code from pkg/manager to pkg/endpoints
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-24 08:07:23 +02:00
Patryk Strusiewicz-Surmacki
ae2571e241 Refactoring endpoint-watcher code
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-24 08:07:23 +02:00
Patryk Strusiewicz-Surmacki
86f5e9b8b2 Removed insecure client use in E2E tests
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-24 08:07:00 +02:00
Patryk Strusiewicz-Surmacki
ce61ff085a Use insecure client only in E2E tests
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-21 17:54:12 +02:00
dependabot[bot]
b816e154cf Bump golang from 1.24.4-alpine3.22 to 1.24.5-alpine3.22
Bumps golang from 1.24.4-alpine3.22 to 1.24.5-alpine3.22.

---
updated-dependencies:
- dependency-name: golang
  dependency-version: 1.24.5-alpine3.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 03:15:14 +00:00
Patryk Strusiewicz-Surmacki
ac1238c337 Rebase
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-10 17:50:15 +02:00
Patryk Strusiewicz-Surmacki
10dbf2c0ef Refactoring endpoint-watcher code
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-10 17:50:15 +02:00
Jan-Philipp Litza
cf68f8639c Add VIPs as deprecated
This causes IPv6 source address selection according to RFC 3484 to
ignore VIPs when choosing which address the host should use for egress
communication.

Signed-off-by: Jan-Philipp Litza <janphilipp@litza.de>
2025-07-09 10:54:28 +02:00
Daniel Finneran
b114c11b0f Merge pull request #1191 from kube-vip/thebsdbox-patch-1
Update README.md
2025-07-03 09:59:49 +01:00
Patryk Strusiewicz-Surmacki
42b7a8152b Basic e2e tests for BGP mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-07-01 12:36:33 +02:00
mushrushu
f7821c7fb3 fixed vars formatting & log statement
Signed-off-by: mushrushu <mushrushu@outlook.com>
2025-07-01 12:34:43 +02:00
mushrushu
42478905d0 added zebra integration and its configuration
Signed-off-by: mushrushu <mushrushu@outlook.com>
2025-07-01 12:34:43 +02:00
dependabot[bot]
8d55bd3b63 Bump github.com/vishvananda/netlink from 1.3.0 to 1.3.1
Bumps [github.com/vishvananda/netlink](https://github.com/vishvananda/netlink) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/vishvananda/netlink/releases)
- [Commits](https://github.com/vishvananda/netlink/compare/v1.3.0...v1.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-30 03:20:14 +00:00
Daniel Finneran
16247fc3a3 Update README.md
Adds health of project badges! (looking healthy) 😄
2025-06-27 14:20:14 +01:00
Marcel Fest
b56b80cd30 Bump version to v0.9.2
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-24 19:02:31 +02:00
dependabot[bot]
ba25e0e583 Bump github.com/prometheus/client_golang from 1.21.0 to 1.22.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.21.0 to 1.22.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.21.0...v1.22.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-24 18:59:16 +02:00
dependabot[bot]
8f1fe355fc Bump github.com/onsi/gomega from 1.36.2 to 1.37.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.36.2 to 1.37.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.36.2...v1.37.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-24 16:29:41 +02:00
dependabot[bot]
649d9bf0ef Bump golang.org/x/sys from 0.32.0 to 0.33.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.32.0 to 0.33.0.
- [Commits](https://github.com/golang/sys/compare/v0.32.0...v0.33.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 09:20:35 +02:00
dependabot[bot]
a5108a69aa Bump anchore/sbom-action from 0.19.0 to 0.20.1
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.19.0 to 0.20.1.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.19.0...v0.20.1)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-20 17:53:00 +02:00
dependabot[bot]
c74a496299 Bump go.etcd.io/etcd/client/v3 from 3.5.18 to 3.6.1
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.18 to 3.6.1.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.18...v3.6.1)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-version: 3.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-17 12:06:43 +02:00
dependabot[bot]
b74c274466 Bump alpine from 3.21.3 to 3.22.0
Bumps alpine from 3.21.3 to 3.22.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-17 11:57:04 +02:00
Dan Finneran
56b3867e57 typo fix 2025-06-17 11:56:43 +02:00
Dan Finneran
66d237bfbc adds kernel module check for nftables 2025-06-17 11:56:43 +02:00
Patryk Strusiewicz-Surmacki
68071b214e Fixed BGP clear deadlock
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-06-17 11:55:49 +02:00
Patryk Strusiewicz-Surmacki
a82ca5576b Updated go version to 1.24.4
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-06-17 09:53:57 +02:00
Patryk Strusiewicz-Surmacki
81dd386b4e Fixed service-tests
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
Co-authored-by: Marcel Fest <marcel@fest4.eu>
2025-06-10 22:26:02 +02:00
Patryk Strusiewicz-Surmacki
b61a74396d Moved configuredRoutes map to serviceContext struct
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-06-10 22:26:02 +02:00
Daniel Finneran
105fbc522a Merge pull request #1163 from p-strusiewiczsurmacki-mobica/rt-tests
Added ARP/NDP services tests and Routing Table services tests
2025-06-10 11:34:15 -07:00
Dan Finneran
2b52c39242 Small change to reduce pointless errors 2025-06-10 13:31:06 +02:00
Patryk Strusiewicz-Surmacki
25d39bca09 Added TODO for insecure discovery client
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-06-06 16:18:38 +02:00
Marcel Fest
644226321e fix typo
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
3928dda541 move lock for cleanRoutes feature at start of kube-vip
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Patryk Strusiewicz-Surmacki
d9a7f413a6 Moved code to use sync.Maps
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Patryk Strusiewicz-Surmacki
eb300bb634 Fixed deadlock
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
c30fd9e7be fix tests + refactor func
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
2fc969b848 Move the check into the function
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
47884088ec remove AI code
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
70e1212396 remove redundant condition
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
d947c2abcc refactor syncServices to be lockable at all
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
e2efb64aea Use the mutext in callbacks as well
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Marcel Fest
01279d45e3 Added function to create ip array from statu LB ingress field
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-06-05 17:26:55 +02:00
Patryk Strusiewicz-Surmacki
f2a7cad218 Added ARP/NDP services tests and Routing Table services tests
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-05-23 11:59:14 +02:00
Nathan Przybyszewski
98163341d3 Replace invalid verb "endpoints" with "update"
Signed-off-by: Nathan Przybyszewski <172687074+nprzy@users.noreply.github.com>
2025-05-01 10:28:43 +02:00
Marcel Fest
a71d361d15 Bump version
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-28 16:33:49 +02:00
dependabot[bot]
cf24ad835d Bump github.com/onsi/ginkgo/v2 from 2.22.2 to 2.23.4
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.22.2 to 2.23.4.
- [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/v2.22.2...v2.23.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 14:21:36 +02:00
dependabot[bot]
0c04088b16 Bump github.com/cloudflare/ipvs from 0.10.3 to 0.11.0
Bumps [github.com/cloudflare/ipvs](https://github.com/cloudflare/ipvs) from 0.10.3 to 0.11.0.
- [Release notes](https://github.com/cloudflare/ipvs/releases)
- [Commits](https://github.com/cloudflare/ipvs/compare/v0.10.3...v0.11.0)

---
updated-dependencies:
- dependency-name: github.com/cloudflare/ipvs
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 14:07:42 +02:00
dependabot[bot]
22489ad095 Bump golang.org/x/sys from 0.31.0 to 0.32.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.31.0 to 0.32.0.
- [Commits](https://github.com/golang/sys/compare/v0.31.0...v0.32.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 14:07:29 +02:00
dependabot[bot]
1fa3da45fa Bump github.com/gookit/slog from 0.5.7 to 0.5.8
Bumps [github.com/gookit/slog](https://github.com/gookit/slog) from 0.5.7 to 0.5.8.
- [Release notes](https://github.com/gookit/slog/releases)
- [Commits](https://github.com/gookit/slog/compare/v0.5.7...v0.5.8)

---
updated-dependencies:
- dependency-name: github.com/gookit/slog
  dependency-version: 0.5.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 14:07:18 +02:00
Patryk Strusiewicz-Surmacki
d497df3767 Fixed instance finding and route deletion in RT mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-28 14:06:20 +02:00
dependabot[bot]
bdd3c5c191 Bump anchore/sbom-action from 0.18.0 to 0.19.0
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.18.0 to 0.19.0.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-version: 0.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 07:17:13 +02:00
Shawn Wilsher
5b41db2246 feat: Add opencontainers annotations during release
This change relies on `docker/metadata-action` to generate the
appropriate labels.

Fixes #1044

Signed-off-by: Shawn Wilsher <656602+sdwilsh@users.noreply.github.com>
2025-04-27 21:52:29 +02:00
Shawn Wilsher
1eb35774a5 fix: s/endoints/endpoints/ in RBAC manifest generation code
While moving over to using the RBAC manifest generator, this stood out as a clear typo.

Signed-off-by: Shawn Wilsher <me@shawnwilsher.com>
2025-04-27 09:27:12 +02:00
Daniel Finneran
7d7036fae9 Merge pull request #1130 from kube-vip/fix/upnp
fix #1127 as we have a nil deref if router does not support IPv6
2025-04-15 17:15:23 +01:00
Marcel Fest
1a4bf13819 fix #1127 as we have a nil deref if router does not support IPv6
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 23:20:29 +02:00
dependabot[bot]
3e225bf51f Bump go.etcd.io/etcd/api/v3 from 3.5.18 to 3.5.21
Bumps [go.etcd.io/etcd/api/v3](https://github.com/etcd-io/etcd) from 3.5.18 to 3.5.21.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.18...v3.5.21)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/api/v3
  dependency-version: 3.5.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 23:16:09 +02:00
dependabot[bot]
d6837cbe7d Bump github.com/osrg/gobgp/v3 from 3.35.0 to 3.36.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.35.0 to 3.36.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.35.0...v3.36.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-version: 3.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 22:56:35 +02:00
dependabot[bot]
40994e0464 Bump go.etcd.io/etcd/client/pkg/v3 from 3.5.18 to 3.5.21
Bumps [go.etcd.io/etcd/client/pkg/v3](https://github.com/etcd-io/etcd) from 3.5.18 to 3.5.21.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.18...v3.5.21)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/pkg/v3
  dependency-version: 3.5.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 22:54:20 +02:00
dependabot[bot]
4e18ad189d Bump google.golang.org/protobuf from 1.36.5 to 1.36.6
Bumps google.golang.org/protobuf from 1.36.5 to 1.36.6.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-version: 1.36.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 22:39:06 +02:00
dependabot[bot]
a0ed07913e Bump golang.org/x/sync from 0.11.0 to 0.13.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.11.0 to 0.13.0.
- [Commits](https://github.com/golang/sync/compare/v0.11.0...v0.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-14 22:20:57 +02:00
Patryk Strusiewicz-Surmacki
3d9ca62031 Removed dependancy for endpoint counter in ARP mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Patryk Strusiewicz-Surmacki
e0f4520437 Fixed ARP multiple references issues
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk.pawel.strusiewicz-surmacki@external.telekom.de>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
3a5ebd184d Setup ipv4 and ipv6 subnet mask in template
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
a7d19c15f1 rename forgotten envvar
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
9822d92bed remove wrong if condition
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
4d8b7750ae fix error wrap
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Patryk Strusiewicz-Surmacki
3bcf783020 Fixed E2E tests
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
1b3a7bb5de improved log messages
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
0d5ac98209 Simplify validation check and remove unused code
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
e2472e509b fix tests?
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
08388496bc Updated logic to not be as redundant
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
f4eab023e8 Refactor and condense code, we always want to set SubnetMask
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
c5e854f323 Breaking: Remove vip_cidr in favor of vip_subnet from config interface
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
e7b9439161 Breaking Change do to retirement of vip_cidr
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
555ca2b830 fix ci
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Marcel Fest
271f21f203 Try to add dual-stack support for BGP mode
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-14 21:41:34 +02:00
Daniel Finneran
de54fcbd11 Merge pull request #1126 from kube-vip/add/rbac-manifest-generation
Added support for RBAC manifest generation
2025-04-10 15:50:40 +01:00
Patryk Strusiewicz-Surmacki
46cad395e1 Fixed service IP address deletion on service modification bug
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-09 23:15:43 +02:00
Marcel Fest
3466947f69 Added doc string for RBAC manifest generation
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 23:06:22 +02:00
Marcel Fest
8696f80525 added missing inCluster flag back
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 23:06:22 +02:00
Marcel Fest
51527d3e6c Added support for RBAC manifest generation
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 23:06:20 +02:00
Marcel Fest
c8a9189bf6 Remove the packet env var constants
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 21:11:39 +02:00
Deveshi Dwivedi
896b0983e4 remove remaining providerConfig references
Signed-off-by: Deveshi Dwivedi <deveshigurgaon@gmail.com>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 21:11:39 +02:00
Deveshi Dwivedi
d55b124251 change annotations format back
Signed-off-by: Deveshi Dwivedi <deveshigurgaon@gmail.com>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 21:11:39 +02:00
Deveshi Dwivedi
72b6e22d90 remove equinix-metal code
Signed-off-by: Deveshi Dwivedi <deveshigurgaon@gmail.com>
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2025-04-09 21:11:39 +02:00
Marcel Fest
3272bc1f8b Update golang-ci-lint to use kubernetes 1.24.x 2025-04-04 16:54:39 +02:00
dependabot[bot]
1e754703e8 Bump k8s.io/client-go from 0.32.1 to 0.32.3
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.32.1 to 0.32.3.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.32.1...v0.32.3)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-04 16:54:39 +02:00
dependabot[bot]
119424bb9b Bump k8s.io/api from 0.32.1 to 0.32.3
Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.32.1 to 0.32.3.
- [Commits](https://github.com/kubernetes/api/compare/v0.32.1...v0.32.3)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-04 16:54:39 +02:00
Marcel Fest
d8926ebea5 bump golang 2025-04-04 16:54:39 +02:00
dependabot[bot]
6b1a0a7ea8 Bump github.com/osrg/gobgp/v3 from 3.34.0 to 3.35.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.34.0 to 3.35.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.34.0...v3.35.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-03 16:52:27 +02:00
dependabot[bot]
c92d01b957 Bump golang.org/x/net from 0.34.0 to 0.36.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.34.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.34.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-03 16:51:26 +02:00
dependabot[bot]
d6c6d8e529 Bump sigs.k8s.io/kind from 0.26.0 to 0.27.0
Bumps [sigs.k8s.io/kind](https://github.com/kubernetes-sigs/kind) from 0.26.0 to 0.27.0.
- [Release notes](https://github.com/kubernetes-sigs/kind/releases)
- [Commits](https://github.com/kubernetes-sigs/kind/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/kind
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-03 16:50:41 +02:00
dependabot[bot]
1d086b2d5c Bump golang from 1.24.0-alpine3.20 to 1.24.1-alpine3.20
Bumps golang from 1.24.0-alpine3.20 to 1.24.1-alpine3.20.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-03 16:49:48 +02:00
dependabot[bot]
e5d967dcf4 Bump github.com/spf13/cobra from 1.8.1 to 1.9.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.1 to 1.9.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.1...v1.9.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-03 16:49:15 +02:00
Patryk Strusiewicz-Surmacki
21a5533936 Fixes for IPv6 and dualstack clusters
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
d21fec6c7d Cancel leaderelection if forwarding mode is local and no local endpoints are present
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
9c4ae86937 Added IPv6 related configuration for IPVS
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
9c67660b94 Added permission check for IPVS info
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
96d020b6ad Disable IPVS related iptables rules if LB is not enabled
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
bc42c3e2c3 Added sysctl check
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
ea45dafcf3 Fixed IPVS deletion issues
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:19:06 +02:00
Patryk Strusiewicz-Surmacki
3e3fd21c16 Fixed route deletion issue when 2 services referenced same endpoint
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-04-03 16:04:11 +02:00
Patryk Strusiewicz-Surmacki
70b83664a9 Less strict service status update error handling
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-03-27 15:27:26 +01:00
Patryk Strusiewicz-Surmacki
9650a00157 Fixed service/endpoints discovery concurrent issue
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-03-10 12:12:23 +01:00
Patryk Strusiewicz-Surmacki
f851ddbcaf Fixed service update in BGP and ARP mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-03-08 08:43:00 +01:00
Daniel Finneran
a5ee4d969b Merge pull request #1091 from p-strusiewiczsurmacki-mobica/ipvs-re-add-cp
Fixed IPVS backend re-add
2025-03-06 17:15:24 +01:00
Patryk Strusiewicz-Surmacki
2dfd46decb Fixed IPVS backend re-add
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-03-04 15:42:45 +01:00
Daniel Finneran
6752dc0fdd Merge pull request #1084 from kube-vip/dependabot/go_modules/github.com/prometheus/client_golang-1.21.0
Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0
2025-02-26 15:45:38 +01:00
Daniel Finneran
c7174d3c94 Merge pull request #1083 from kube-vip/dependabot/go_modules/github.com/google/go-cmp-0.7.0
Bump github.com/google/go-cmp from 0.6.0 to 0.7.0
2025-02-26 15:45:25 +01:00
Daniel Finneran
d33ba7e22e Merge pull request #1079 from kube-vip/health
This adds a health check
2025-02-26 15:44:29 +01:00
dependabot[bot]
9b552a4d29 Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.21.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.21.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 02:57:33 +00:00
dependabot[bot]
5fc04a24f8 Bump github.com/google/go-cmp from 0.6.0 to 0.7.0
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.6.0...v0.7.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-24 02:57:30 +00:00
Daniel Finneran
122b18a81d Merge pull request #1070 from kube-vip/dependabot/go_modules/google.golang.org/protobuf-1.36.5
Bump google.golang.org/protobuf from 1.36.1 to 1.36.5
2025-02-20 12:42:39 +01:00
Daniel Finneran
c9bc005abe Merge pull request #1075 from kube-vip/dependabot/go_modules/github.com/cloudflare/ipvs-0.10.3
Bump github.com/cloudflare/ipvs from 0.10.2 to 0.10.3
2025-02-20 12:42:26 +01:00
Daniel Finneran
ee0f0668ab Merge pull request #1076 from kube-vip/dependabot/docker/alpine-3.21.3
Bump alpine from 3.21.2 to 3.21.3
2025-02-20 12:42:09 +01:00
Daniel Finneran
826bb6fc8a Merge pull request #1077 from kube-vip/dependabot/docker/golang-1.24.0-alpine3.20
Bump golang from 1.23.5-alpine3.20 to 1.24.0-alpine3.20
2025-02-20 12:41:57 +01:00
Dan Finneran
b9aa99a208 more lint goodness 2025-02-17 17:23:01 +00:00
Dan Finneran
2b0aa825b5 lint fix 2025-02-17 17:21:20 +00:00
dependabot[bot]
24b1524aee Bump google.golang.org/protobuf from 1.36.1 to 1.36.5
Bumps google.golang.org/protobuf from 1.36.1 to 1.36.5.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 17:18:22 +00:00
Daniel Finneran
cf7c7f2f25 Merge pull request #1069 from kube-vip/dependabot/go_modules/golang.org/x/sync-0.11.0
Bump golang.org/x/sync from 0.10.0 to 0.11.0
2025-02-17 18:17:01 +01:00
Dan Finneran
c082688e67 This adds a health check 2025-02-17 17:16:29 +00:00
dependabot[bot]
18bfe6a8d2 Bump golang.org/x/sync from 0.10.0 to 0.11.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/sync/compare/v0.10.0...v0.11.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 15:16:50 +00:00
Daniel Finneran
c367434798 Merge pull request #1068 from kube-vip/dependabot/go_modules/github.com/osrg/gobgp/v3-3.34.0
Bump github.com/osrg/gobgp/v3 from 3.33.0 to 3.34.0
2025-02-17 16:15:09 +01:00
Daniel Finneran
f1ca914e92 Merge pull request #1067 from kube-vip/dependabot/go_modules/golang.org/x/sys-0.30.0
Bump golang.org/x/sys from 0.29.0 to 0.30.0
2025-02-17 16:14:57 +01:00
Daniel Finneran
2763c7e417 Merge pull request #1072 from p-strusiewiczsurmacki-mobica/mask-fix
Fixed network mask setting function
2025-02-17 16:14:43 +01:00
Daniel Finneran
f9f0004d3f Merge pull request #1064 from kube-vip/resolver
Resolver, this will ensure that an address that is not an IP address is resolved first to determine the CIDR
2025-02-17 16:14:22 +01:00
Daniel Finneran
958eaefb40 Merge pull request #1062 from kube-vip/bgp_port
You can now specify the port as the fifth argument to peer config
2025-02-17 16:14:05 +01:00
Daniel Finneran
3752695000 Merge pull request #1060 from kube-vip/waitgroup
remove the waitgroups as we never wait
2025-02-17 16:13:38 +01:00
Daniel Finneran
d6eb7c4f26 Merge pull request #1059 from kube-vip/drop_all
drop all other capabilities
2025-02-17 16:13:21 +01:00
dependabot[bot]
b88769e109 Bump golang from 1.23.5-alpine3.20 to 1.24.0-alpine3.20
Bumps golang from 1.23.5-alpine3.20 to 1.24.0-alpine3.20.

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 02:38:59 +00:00
dependabot[bot]
eddbcf0801 Bump alpine from 3.21.2 to 3.21.3
Bumps alpine from 3.21.2 to 3.21.3.

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 02:38:56 +00:00
dependabot[bot]
886f183108 Bump github.com/cloudflare/ipvs from 0.10.2 to 0.10.3
Bumps [github.com/cloudflare/ipvs](https://github.com/cloudflare/ipvs) from 0.10.2 to 0.10.3.
- [Release notes](https://github.com/cloudflare/ipvs/releases)
- [Commits](https://github.com/cloudflare/ipvs/compare/v0.10.2...v0.10.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-17 02:15:06 +00:00
Patryk Strusiewicz-Surmacki
aba1d53699 Changed initConfig.Logging to be int32
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-02-13 19:36:39 +01:00
Patryk Strusiewicz-Surmacki
d05530e030 Fixed logging level configuration with command line argument
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-02-13 19:36:39 +01:00
Patryk Strusiewicz-Surmacki
7d52dbbbd5 Return error instead of logging warning
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-02-12 11:51:07 +01:00
Patryk Strusiewicz-Surmacki
53185bd58d Fixed ENV log level setting
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-02-10 21:24:48 +01:00
Patryk Strusiewicz-Surmacki
8997c4b1a8 Fixed network mask setting function
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-02-10 15:46:55 +01:00
dependabot[bot]
ce4665bbec Bump github.com/osrg/gobgp/v3 from 3.33.0 to 3.34.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.33.0 to 3.34.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.33.0...v3.34.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-10 02:10:52 +00:00
dependabot[bot]
e1ecca42c5 Bump golang.org/x/sys from 0.29.0 to 0.30.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.29.0 to 0.30.0.
- [Commits](https://github.com/golang/sys/compare/v0.29.0...v0.30.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>
2025-02-10 02:10:48 +00:00
Dan Finneran
c6cb548763 This ensures a hostname is resolved if passed as the api address 2025-02-05 14:51:22 +00:00
Dan Finneran
b52c90f865 You can now specify the port as the fifth argument to peer config 2025-02-05 13:37:41 +00:00
Daniel Finneran
2ceba7f5ad Update ci.yaml
Remove the original control plane tests as everything is 1.29+ at this point
2025-02-05 12:32:22 +00:00
Daniel Finneran
c3121a97f1 Update README.md 2025-02-05 12:29:53 +00:00
Daniel Finneran
b7cc63bfd6 Merge pull request #1048 from kube-vip/dependabot/go_modules/k8s.io/api-0.32.1
Bump k8s.io/api from 0.32.0 to 0.32.1
2025-02-05 12:41:22 +01:00
Daniel Finneran
3a4d859457 Merge pull request #1047 from kube-vip/dependabot/go_modules/k8s.io/client-go-0.32.1
Bump k8s.io/client-go from 0.32.0 to 0.32.1
2025-02-05 12:41:02 +01:00
Dan Finneran
964b248108 remove the waitgroups as we never wait 2025-02-05 11:37:48 +00:00
Daniel Finneran
b6e87418a2 Merge pull request #1055 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.18
Bump go.etcd.io/etcd/client/v3 from 3.5.17 to 3.5.18
2025-02-05 12:01:27 +01:00
Dan Finneran
473fd6f4f8 drop all other capabilities 2025-02-05 09:58:14 +00:00
Daniel Finneran
c49afdb44d Merge branch 'main' into dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.18 2025-02-05 10:56:55 +01:00
dependabot[bot]
f0182fcb0c Bump k8s.io/api from 0.32.0 to 0.32.1
Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.32.0 to 0.32.1.
- [Commits](https://github.com/kubernetes/api/compare/v0.32.0...v0.32.1)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-05 09:55:47 +00:00
Daniel Finneran
7424df98a5 Merge pull request #1054 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/client/pkg/v3-3.5.18
Bump go.etcd.io/etcd/client/pkg/v3 from 3.5.17 to 3.5.18
2025-02-05 10:55:39 +01:00
Daniel Finneran
b4c4cfd365 Merge pull request #1053 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.18.0
Bump anchore/sbom-action from 0.17.9 to 0.18.0
2025-02-05 10:55:27 +01:00
Daniel Finneran
7878be3847 Merge branch 'main' into dependabot/go_modules/k8s.io/client-go-0.32.1 2025-02-05 10:54:25 +01:00
Daniel Finneran
1dc75f9f21 Merge pull request #1046 from kube-vip/dependabot/go_modules/k8s.io/apimachinery-0.32.1
Bump k8s.io/apimachinery from 0.32.0 to 0.32.1
2025-02-05 10:53:34 +01:00
Daniel Finneran
cbe4cd150e Merge pull request #1043 from kube-vip/slog
Refactor to slog
2025-02-05 10:53:12 +01:00
Dan Finneran
99e1fb3fc6 linting 2025-02-05 09:38:20 +00:00
Dan Finneran
e1481db95c cleanup of messages 2025-02-05 09:24:39 +00:00
Daniel Finneran
efc7ba5646 Merge pull request #1045 from kube-vip/dependabot/docker/golang-1.23.5-alpine3.20
Bump golang from 1.23.4-alpine3.20 to 1.23.5-alpine3.20
2025-02-04 11:50:23 +00:00
Daniel Finneran
90552b73dc Merge pull request #1003 from p-strusiewiczsurmacki-mobica/feature/mp-bgp
Support for MP-BGP
2025-02-04 11:42:17 +00:00
Dan Finneran
81c0b4faf5 lint fix 2025-02-04 08:42:42 +00:00
Dan Finneran
95be514b8f fixes to slog formatting 2025-02-01 14:01:27 +00:00
Daniel Finneran
d289efc862 Merge branch 'main' into slog 2025-02-01 12:18:26 +00:00
Daniel Finneran
e388b2d1c9 Merge pull request #1056 from kube-vip/ndp_error
Ndp error
2025-02-01 12:12:52 +00:00
Dan Finneran
7ca0d79250 superflous error return 2025-02-01 11:49:09 +00:00
Dan Finneran
20b375770c reduced duplicated code and cleaned messages 2025-02-01 11:44:28 +00:00
Dan Finneran
6b3ada8402 NDP link-local messages 2025-02-01 11:07:48 +00:00
Dan Finneran
c12bb65b4b adds some testing for Cilium, not for CI 2025-01-29 14:27:05 +00:00
dependabot[bot]
2e0dddba60 Bump go.etcd.io/etcd/client/v3 from 3.5.17 to 3.5.18
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.17 to 3.5.18.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.17...v3.5.18)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 02:24:49 +00:00
dependabot[bot]
8e6767c606 Bump go.etcd.io/etcd/client/pkg/v3 from 3.5.17 to 3.5.18
Bumps [go.etcd.io/etcd/client/pkg/v3](https://github.com/etcd-io/etcd) from 3.5.17 to 3.5.18.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.17...v3.5.18)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/pkg/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 02:24:45 +00:00
dependabot[bot]
419051c762 Bump anchore/sbom-action from 0.17.9 to 0.18.0
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.9 to 0.18.0.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.17.9...v0.18.0)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-27 02:09:46 +00:00
Dan Finneran
9e432d1178 Fixes to swallowed errors 2025-01-24 09:20:55 +00:00
Patryk Strusiewicz-Surmacki
0832a7227c Added MP-BGP for IPv4 over IPv6 session and config flags
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2025-01-22 17:36:39 +01:00
Christopher Dziomba
3b16caa38c Messy prototype of MP-BGP with kube-vip 2025-01-21 12:10:07 +01:00
dependabot[bot]
1d4e57a754 Bump k8s.io/client-go from 0.32.0 to 0.32.1
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.32.0 to 0.32.1.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.32.0...v0.32.1)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 02:36:19 +00:00
dependabot[bot]
c36585ce98 Bump k8s.io/apimachinery from 0.32.0 to 0.32.1
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.32.0 to 0.32.1.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.0...v0.32.1)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 02:36:11 +00:00
dependabot[bot]
af1280be1a Bump golang from 1.23.4-alpine3.20 to 1.23.5-alpine3.20
Bumps golang from 1.23.4-alpine3.20 to 1.23.5-alpine3.20.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-20 02:32:12 +00:00
Dan Finneran
c01fb8fca7 fix_spelling 2025-01-16 18:39:02 +00:00
Dan Finneran
1d6d860153 set default loglevel 2025-01-16 17:46:11 +00:00
Dan Finneran
2136e69a82 Big refactor to log/slog 2025-01-16 17:45:09 +00:00
Daniel Finneran
cb438d289b Merge pull request #1040 from kube-vip/restart_on_modification
Restart on modification
2025-01-16 12:50:20 +00:00
Dan Finneran
ded08ddf5c Fixing nits 2025-01-16 10:45:36 +00:00
Dan Finneran
79b24875ec le sigh 2025-01-16 09:46:18 +00:00
Daniel Finneran
b423cbdb89 Merge branch 'main' into restart_on_modification 2025-01-16 09:26:52 +00:00
Daniel Finneran
600c1db24b Merge pull request #1036 from kube-vip/logic_clean
This removes some weird pointless code
2025-01-16 09:25:56 +00:00
Dan Finneran
b2979be25c Linting fixes 2025-01-15 11:19:09 +00:00
Dan Finneran
462b511b9f This change means that a modification to an existing LB results in updating the settings. 2025-01-15 11:10:19 +00:00
Daniel Finneran
19e660d4a6 Update Makefile 2025-01-14 13:29:35 +00:00
Daniel Finneran
cfa11d1a88 Merge pull request #1037 from kube-vip/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.22.2
Bump github.com/onsi/ginkgo/v2 from 2.22.1 to 2.22.2
2025-01-14 13:29:16 +00:00
Daniel Finneran
bf283f1252 Merge pull request #1038 from kube-vip/dependabot/docker/alpine-3.21.2
Bump alpine from 3.21.0 to 3.21.2
2025-01-14 13:29:00 +00:00
dependabot[bot]
839b860eee Bump alpine from 3.21.0 to 3.21.2
Bumps alpine from 3.21.0 to 3.21.2.

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 02:54:42 +00:00
dependabot[bot]
e134e5682e Bump github.com/onsi/ginkgo/v2 from 2.22.1 to 2.22.2
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.22.1 to 2.22.2.
- [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/v2.22.1...v2.22.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 02:26:18 +00:00
Dan Finneran
ebc4cdccb9 more_lint 2025-01-12 13:02:08 +00:00
Dan Finneran
baed70dbfc fix_linting 2025-01-12 12:53:05 +00:00
Dan Finneran
b8aff1d348 fix_lint 2025-01-12 12:52:58 +00:00
Dan Finneran
aa5f0cc267 This removes some weird pointless code 2025-01-12 11:36:30 +00:00
Daniel Finneran
316c3bbdd4 Merge pull request #1034 from murphp15/feature/release_the_lock_if_you_cant_advertise_service
release lock if unable to sync service correctly.
2025-01-10 16:17:37 +00:00
paul.murphy
dbc02485d9 release lock if unable to sync service correctly. 2025-01-10 15:54:08 +00:00
paul.murphy
6442ce26fc release lock if unable to sync service correctly. 2025-01-10 15:37:41 +00:00
Paul Murphy
ccd1137606 Merge branch 'kube-vip:main' into feature/release_the_lock_if_you_cant_advertise_service 2025-01-10 14:47:32 +00:00
Daniel Finneran
96d79774b5 Merge pull request #1035 from kube-vip/print_build_info
by default print build
2025-01-10 14:22:12 +00:00
Dan Finneran
829a1fced6 by default print build 2025-01-10 14:20:35 +00:00
paul.murphy
0c5dd3c890 release lock if unable to sync service correctly. 2025-01-10 10:49:51 +00:00
paul.murphy
51aad755c3 release lock if unable to sync service correctly. 2025-01-10 10:49:34 +00:00
paul.murphy
635950e329 release lock if unable to sync service correctly. 2025-01-10 10:45:33 +00:00
paul.murphy
7eb93bec0b Merge branch 'main' into feature/release_the_lock_if_you_cant_advertise_service 2025-01-10 10:39:19 +00:00
paul.murphy
cf8384fb1f release lock if unable to sync service correctly. 2025-01-10 10:36:45 +00:00
Daniel Finneran
6da951056c Merge pull request #1030 from kube-vip/services_fix
Ensure watcher is restarted as expected
2025-01-09 11:35:41 +00:00
Daniel Finneran
a50e476d7e Merge pull request #1029 from kube-vip/watcher-fix
Fixes an issue with watchers having an old reference
2025-01-09 11:21:37 +00:00
Dan Finneran
329e0940da Ensure watcher is restarted as expected 2025-01-09 11:05:03 +00:00
Dan Finneran
7a43646e62 Fixes an issue with watchers having an old reference 2025-01-08 18:27:30 +00:00
Daniel Finneran
dd8f2d13d2 Update Makefile 2025-01-06 13:47:49 +00:00
Daniel Finneran
f119c890a1 Merge pull request #1024 from kube-vip/small_fix
Fix linting issue
2025-01-06 13:46:49 +00:00
Dan Finneran
714b80225f Fix linting issue 2025-01-06 10:52:48 +00:00
Daniel Finneran
49297980b0 Merge pull request #923 from cdtzabra/main
Ensuring nodelabel will be always present
2025-01-06 10:51:31 +00:00
Daniel Finneran
e7beb9c9c3 Merge pull request #1012 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.17.9
Bump anchore/sbom-action from 0.17.5 to 0.17.9
2025-01-06 10:23:02 +00:00
dependabot[bot]
5e66a62c32 Bump anchore/sbom-action from 0.17.5 to 0.17.9
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.5 to 0.17.9.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.17.5...v0.17.9)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-06 09:54:08 +00:00
Daniel Finneran
fbbf83d9d0 Merge pull request #1008 from kube-vip/dependabot/docker/golang-1.23.4-alpine3.20
Bump golang from 1.23.2-alpine3.20 to 1.23.4-alpine3.20
2025-01-06 09:51:24 +00:00
Daniel Finneran
7e244084e1 Merge pull request #1022 from kube-vip/deps
update deps
2025-01-06 09:50:40 +00:00
Dan Finneran
089ad123b6 losing hope 2025-01-05 17:12:35 +00:00
Dan Finneran
fdc50efc86 clutching at straws now 2025-01-05 17:10:24 +00:00
Dan Finneran
7644cb720e attempt 2 2025-01-05 17:05:48 +00:00
Dan Finneran
299c9e1ebb updatae go.mod 2025-01-05 16:02:06 +00:00
Dan Finneran
b82b733dde CI fix 2025-01-05 15:58:58 +00:00
Dan Finneran
e339d12b40 update deps 2025-01-05 15:53:34 +00:00
dependabot[bot]
3ea17b134d Bump golang from 1.23.2-alpine3.20 to 1.23.4-alpine3.20
Bumps golang from 1.23.2-alpine3.20 to 1.23.4-alpine3.20.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-05 15:30:03 +00:00
Daniel Finneran
ea410e7490 Merge pull request #1007 from kube-vip/dependabot/docker/alpine-3.21.0
Bump alpine from 3.20.3 to 3.21.0
2025-01-05 15:29:04 +00:00
Daniel Finneran
430efae598 Merge pull request #1019 from kube-vip/egress_annotations
Adds a bunch of flexability around egress
2025-01-05 15:27:29 +00:00
Dan Finneran
c96cdb6cd2 test fix 2025-01-05 15:03:53 +00:00
Dan Finneran
ffe2e9c808 Various fixes to CI 2025-01-05 14:59:51 +00:00
Dan Finneran
545f9a4a47 fix to modules and workflow 2024-12-20 16:38:56 +00:00
Dan Finneran
2555dd8101 Adds a bunch of flexability around egress 2024-12-20 16:25:06 +00:00
dependabot[bot]
f7b4ab5b42 Bump alpine from 3.20.3 to 3.21.0
Bumps alpine from 3.20.3 to 3.21.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-09 02:39:44 +00:00
Daniel Finneran
4c70d87381 Update Makefile 2024-11-20 09:08:47 +00:00
Dan Finneran
894e56458f remove commented out code 2024-11-15 17:07:51 +01:00
Dan Finneran
de5659e7b2 Services aren't removed when there are no endpoints. 2024-11-15 17:07:51 +01:00
Marcel Fest
e4b0b2a71f Use the new release version in Makefile
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2024-11-11 08:56:48 +01:00
Daniel Finneran
dd06c3fb82 Merge pull request #987 from p-strusiewiczsurmacki-mobica/rwclient-ipvs-fix
Fixed null pointer exception when IPVS loadbalancer is used
2024-11-04 11:31:28 +00:00
Patryk Strusiewicz-Surmacki
8ee952cf3e Fixed null pointer exception when IPVS loadbalancer is used
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-11-04 11:50:34 +01:00
Daniel Finneran
57bcea9646 Merge pull request #984 from kube-vip/fix/retry-watch
initialize the config for the rwclient separately
2024-11-01 11:33:00 +00:00
Cellebyte
907696a4a3 initialize the config for the rwclient separately
Signed-off-by: Cellebyte <marcel.fest@live.de>
2024-11-01 10:50:09 +01:00
Daniel Finneran
78cdf8d5b6 Merge pull request #981 from kube-vip/New-release-0.8.5 2024-10-31 12:59:10 +00:00
Daniel Finneran
5a7edbe825 Merge pull request #976 from l0wl3vel/upnp-gateway-ip 2024-10-31 12:47:35 +00:00
Daniel Finneran
de8300a40a Merge pull request #961 from p-strusiewiczsurmacki-mobica/auto-svc-subnet 2024-10-31 12:46:10 +00:00
Patryk Strusiewicz-Surmacki
73e6ade0ea Added auto subnet discovery for services in ARP mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-31 10:31:39 +01:00
Benjamin Ritter
4def2c784e Update Gateway IPs on UPNP refresh
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-30 17:51:00 +01:00
Benjamin Ritter
1c8ce223d7 Reduce UPNP refresh interval to 5 minutes
Reduces impact on availibility when the
gateway external IP changes

Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-30 17:51:00 +01:00
Benjamin Ritter
02d00bf99c Annotate UPNP Gateway IPs on the service
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-30 17:51:00 +01:00
Daniel Finneran
4433243fa6 Update Makefile
This PR should be the last merged PR for the 0.8.5 release, which should also be the last of the `0.8.x` releases.
2024-10-30 15:21:43 +00:00
Daniel Finneran
a8ae976bb2 Merge pull request #968 from kube-vip/dependabot/go_modules/github.com/cloudflare/ipvs-0.10.2
Bump github.com/cloudflare/ipvs from 0.10.1 to 0.10.2
2024-10-30 14:38:40 +00:00
Daniel Finneran
1559b21cfb Merge pull request #954 from l0wl3vel/upnp-igd2
Use IGD:2 and Pinhole Port Forwarding
2024-10-30 14:37:34 +00:00
Daniel Finneran
f55aed4382 Merge pull request #979 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.17.5
Bump anchore/sbom-action from 0.17.3 to 0.17.5
2024-10-30 14:36:21 +00:00
Daniel Finneran
cc12fcb0f6 Merge pull request #970 from p-strusiewiczsurmacki-mobica/egress-rules-fix
Egress rules deletion fix
2024-10-30 14:36:00 +00:00
Patryk Strusiewicz-Surmacki
95dfc47e47 Added info on egress protocol
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-30 14:31:41 +01:00
Patryk Strusiewicz-Surmacki
0bf38f57f7 Fixed logging issues
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
7f4116417c Fixed typo
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
5763400c15 Added safeguards for IP family
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
6b136efff3 Added changes to CIDR discovery from auto-svc-subnet branch
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
1f089fe71c Added routing table ID fix
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
1bc26b5827 Fixed e2e
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
40674a12b6 Fixed route deleting issue in table mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
ef2f6ebaa0 Fixed auto CIDR discovery priority
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-29 11:46:24 +01:00
Patryk Strusiewicz-Surmacki
625030dfb6 Fixed retry-watcher timeout issue (#974)
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-28 20:14:05 +01:00
Benjamin Ritter
779fc5641f Add context to UPNP logging
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-28 15:24:18 +01:00
dependabot[bot]
971e794639 Bump anchore/sbom-action from 0.17.3 to 0.17.5
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.3 to 0.17.5.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.17.3...v0.17.5)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-28 02:36:00 +00:00
Patryk Strusiewicz-Surmacki
89c6002f92 Fixed NDP responder (#973)
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-27 22:27:55 +01:00
Benjamin Ritter
6b0e45da96 Clean up UPNP client handling
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-27 20:50:32 +01:00
Benjamin Ritter
7bde7a4845 feat: Add perpetual UPNP Forward refreshing
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-24 21:54:44 +02:00
Benjamin Ritter
eda0bd69b3 Use IGD:2 and Pinhole Port Forwarding
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-10-24 21:54:30 +02:00
dependabot[bot]
2a56bdb0c8 Bump github.com/cloudflare/ipvs from 0.10.1 to 0.10.2
Bumps [github.com/cloudflare/ipvs](https://github.com/cloudflare/ipvs) from 0.10.1 to 0.10.2.
- [Release notes](https://github.com/cloudflare/ipvs/releases)
- [Commits](https://github.com/cloudflare/ipvs/compare/v0.10.1...v0.10.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 02:20:18 +00:00
Daniel Finneran
de0375610d Merge pull request #965 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.17.3
Bump anchore/sbom-action from 0.17.2 to 0.17.3
2024-10-18 11:18:27 +02:00
Daniel Finneran
382024104a Merge pull request #964 from kube-vip/dependabot/go_modules/github.com/spf13/cobra-1.8.1
Bump github.com/spf13/cobra from 1.8.0 to 1.8.1
2024-10-18 11:18:08 +02:00
dependabot[bot]
e896b55c25 Bump anchore/sbom-action from 0.17.2 to 0.17.3
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.2 to 0.17.3.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.17.2...v0.17.3)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 02:50:27 +00:00
dependabot[bot]
53ce87755a Bump github.com/spf13/cobra from 1.8.0 to 1.8.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 02:31:14 +00:00
Daniel Finneran
750f78164f Merge pull request #918 from kube-vip/dependabot/go_modules/k8s.io/klog/v2-2.130.1
Bump k8s.io/klog/v2 from 2.120.1 to 2.130.1
2024-10-10 09:41:30 +01:00
Daniel Finneran
bf6cb8e39e Merge pull request #887 from kube-vip/dependabot/github_actions/docker/build-push-action-6
Bump docker/build-push-action from 5 to 6
2024-10-10 09:39:55 +01:00
Daniel Finneran
f58e110057 Update Makefile 2024-10-10 09:39:28 +01:00
dependabot[bot]
98db46c817 Bump k8s.io/klog/v2 from 2.120.1 to 2.130.1
Bumps [k8s.io/klog/v2](https://github.com/kubernetes/klog) from 2.120.1 to 2.130.1.
- [Release notes](https://github.com/kubernetes/klog/releases)
- [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes/klog/compare/v2.120.1...v2.130.1)

---
updated-dependencies:
- dependency-name: k8s.io/klog/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-10 08:28:26 +00:00
Daniel Finneran
da9b440f1e Merge pull request #939 from kube-vip/dependabot/docker/alpine-3.20.3
Bump alpine from 3.20.0 to 3.20.3
2024-10-10 09:27:48 +01:00
dependabot[bot]
a18039373d Bump docker/build-push-action from 5 to 6
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-10 08:27:05 +00:00
Daniel Finneran
a9753fafd2 Merge pull request #960 from kube-vip/dependabot/docker/golang-1.23.2-alpine3.20
Bump golang from 1.23.1-alpine3.20 to 1.23.2-alpine3.20
2024-10-10 09:26:45 +01:00
Daniel Finneran
8aa0a6b9e0 Merge pull request #958 from p-strusiewiczsurmacki-mobica/control-plane-table-e2e
Added e2e tests for control-plane in routing table mode, fixed IPv6 issue
2024-10-07 17:00:48 +01:00
dependabot[bot]
8f16021e4c Bump golang from 1.23.1-alpine3.20 to 1.23.2-alpine3.20
Bumps golang from 1.23.1-alpine3.20 to 1.23.2-alpine3.20.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 02:27:00 +00:00
Patryk Strusiewicz-Surmacki
456d52d507 Added e2e tests for control-plane in routing table mode and fixed IPv6 issue
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-03 17:11:57 +02:00
Daniel Finneran
4da24fb64f Merge pull request #957 from p-strusiewiczsurmacki-mobica/control-plane-table-mode
Routing Table mode for Control Plane
2024-10-03 11:27:15 +02:00
Daniel Finneran
c27044b521 Merge pull request #952 from l0wl3vel/upnp-forward-multiple-ports
UPNP: Assume that multiple ports can exist on a service
2024-10-02 13:23:20 +02:00
Patryk Strusiewicz-Surmacki
810cf89f97 Routing Table mode for Control Plane
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-01 18:00:59 +02:00
Patryk Strusiewicz-Surmacki
d65af2c84f Fixed lastKnownGoodEndpoint not being set when in non-leader-election mode (#955)
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-10-01 14:29:42 +02:00
Daniel Finneran
d30fda1d9d Merge pull request #956 from tenyo/lo-iface-scope
Add loInterfaceGlobalScope flag for enabling global scope for vip lo interface
2024-09-30 14:24:42 +02:00
tenyo
b6d4aa1632 add loInterfaceGlobalScope flag for enabling global scope for vip lo interface
Signed-off-by: tenyo <tgrozev@equinix.com>
2024-09-27 20:21:51 +00:00
Benjamin Ritter
b024d04d91 Assume that multiple ports can exist on a service
Fixes UPNP exposing only the port with the lowest numeric value. #951

Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-09-24 16:06:43 +02:00
Daniel Finneran
6cdc7a86c4 Merge pull request #950 from l0wl3vel/upnp-per-service
Enable UPNP Port forwarding per service
2024-09-24 08:47:26 +01:00
Benjamin Ritter
c6f1c740fd feat: Gate UPNP port forwarding behind kube-vip.io/forwardUPNP annotation
Signed-off-by: Benjamin Ritter <Benjamin.Ritter@protonmail.com>
2024-09-22 10:31:32 +02:00
Daniel Finneran
95c43472e9 Update Makefile 2024-09-09 13:34:45 +01:00
dependabot[bot]
c8a222e244 Bump alpine from 3.20.0 to 3.20.3
Bumps alpine from 3.20.0 to 3.20.3.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 08:30:04 +00:00
Daniel Finneran
37abb44a64 Merge pull request #940 from kube-vip/dependabot/docker/golang-1.23.1-alpine3.20
Bump golang from 1.22.6-alpine3.20 to 1.23.1-alpine3.20
2024-09-09 09:25:34 +01:00
dependabot[bot]
b4e6725a1a Bump golang from 1.22.6-alpine3.20 to 1.23.1-alpine3.20
Bumps golang from 1.22.6-alpine3.20 to 1.23.1-alpine3.20.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 02:29:55 +00:00
Daniel Finneran
b6410d9b4d Merge pull request #927 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.17.2
Bump anchore/sbom-action from 0.17.0 to 0.17.2
2024-09-06 16:11:49 +03:00
Daniel Finneran
4bdfeffc96 Merge pull request #937 from thebsdbox/ipv6_egress
This adds ipv6 egress & test
2024-09-06 16:11:35 +03:00
Daniel Finneran
a32804dfee Update pkg/vip/util.go
I like it

Co-authored-by: Patryk Strusiewicz-Surmacki <137421299+p-strusiewiczsurmacki-mobica@users.noreply.github.com>
2024-09-06 12:31:03 +01:00
Dan Finneran
b24ce18d55 Fix test
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-09-05 12:40:24 +00:00
Dan Finneran
5512a08aac restored the exact behaviour for IPv4
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-09-05 12:22:41 +00:00
Dan Finneran
f438367d6e This adds ipv6 egress & test
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-09-05 12:08:39 +00:00
cdtzabra
62a724122c Update node_labeling.go 2024-09-03 12:19:51 +02:00
Daniel Finneran
fb86cb8687 Merge pull request #929 from linsite/cleanup-makefile
clean up Makefile
2024-09-02 15:59:31 +03:00
linmaolin
29a0dc6c07 clean up Makefile
fmt target is stale, just removing it, also simplify target is not working under 1.21 toolchain,
update it as well.

Signed-off-by: Lin Lin <linlin152@foxmail.com>
2024-08-28 11:57:40 +08:00
dependabot[bot]
82f3c6a491 Bump anchore/sbom-action from 0.17.0 to 0.17.2
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.0 to 0.17.2.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.17.0...v0.17.2)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-26 02:53:48 +00:00
Daniel Finneran
fbb2746d07 Merge pull request #926 from p-strusiewiczsurmacki-mobica/svc-auto-interface
Auto network interface discovery for services
2024-08-23 17:55:26 +01:00
Patryk Strusiewicz-Surmacki
185d8bc484 Auto network interface discovery for services
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-08-23 15:15:11 +02:00
cdtzabra
db88185c40 Merge pull request #1 from cdtzabra/cdtzabra-patch-1
Ensuring nodelabel will be always present
2024-08-21 18:24:01 +02:00
cdtzabra
611cb0288f Ensuring nodelabel will be always present 2024-08-21 18:22:57 +02:00
Daniel Finneran
b18bdd0fb9 Merge pull request #872 from kube-vip/dependabot/go_modules/github.com/stretchr/testify-1.9.0
Bump github.com/stretchr/testify from 1.8.4 to 1.9.0
2024-08-15 12:46:28 +01:00
Daniel Finneran
8ef0d459c0 Merge pull request #902 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.17.0
Bump anchore/sbom-action from 0.16.0 to 0.17.0
2024-08-12 15:16:44 +02:00
Daniel Finneran
41bc78bc8f Merge pull request #915 from kube-vip/dependabot/docker/golang-1.22.6-alpine3.20
Bump golang from 1.22.4-alpine3.20 to 1.22.6-alpine3.20
2024-08-12 15:16:30 +02:00
Daniel Finneran
05984b9860 Merge pull request #910 from M0NsTeRRR/fix/ipv6-port-join
fix: ipv6 host and port join
2024-08-12 15:16:13 +02:00
dependabot[bot]
82b1e8536b Bump golang from 1.22.4-alpine3.20 to 1.22.6-alpine3.20
Bumps golang from 1.22.4-alpine3.20 to 1.22.6-alpine3.20.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 02:26:32 +00:00
Daniel Finneran
425cb92dee Merge pull request #904 from M0NsTeRRR/main
fix: set vip_cidr default value
2024-08-07 10:37:53 +02:00
Ludovic Ortega
9470edbea9 fix: ipv6 host and port join
Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
2024-08-07 00:48:59 +02:00
Ludovic Ortega
a5d6846608 fix: set vip_cidr default value
Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
2024-07-23 21:15:12 +02:00
Daniel Finneran
04ce471366 Update Makefile 2024-07-23 09:27:46 +01:00
Daniel Finneran
6c090701ea Merge pull request #897 from TilBlechschmidt/bug/dhcp-renew-failure
Change service interface to `macvlan` when using DHCP
2024-07-23 09:25:41 +01:00
dependabot[bot]
87fd49ac98 Bump anchore/sbom-action from 0.16.0 to 0.17.0
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.16.0 to 0.17.0.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-22 02:47:10 +00:00
Til Blechschmidt
a0a19ea3fa Change service interface to macvlan when using DHCP
When using DHCP for LB services, the resulting IP was assigned to the
`serviceInterface` while most (not all) DHCP communication was done
through a per-service `macvlan` interface that is created on demand.

This has been the cause of DHCP lease renewal failures for some users,
as the response packets from the server never reached kube-vip. For more
details, see issue #871.

To remedy this, the primary interface used for a service is now being
set to the `macvlan`. Consequently, the IP address is also assigned to
it.

As a result, all traffic related to an LB service (DHCP or not) is now
originating from and sent to the per-service `macvlan` interface that
is tied to the user-configured `serviceInterface`.

Fixes #871

Signed-off-by: Til Blechschmidt <me@tibl.dev>
2024-07-19 12:26:43 +02:00
Daniel Finneran
a571d0a9c2 Merge pull request #894 from thebsdbox/manifest_fix
Manifest fix
2024-07-11 09:14:40 +01:00
Dan Finneran
6f267462bb linting fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-07-11 08:03:51 +00:00
Dan Finneran
a52e9a1818 adds CI test
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-07-10 15:24:32 +00:00
Dan Finneran
e883c1ea5d fixes manifest generation
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-07-10 15:15:24 +00:00
Marcel Fest
59951cbd4b [Bugfix] Parse the routingTableID correctly (#889)
* Parse the routingTableID correctly [rtnetlink.h](55027e6899/include/uapi/linux/rtnetlink.h\#L354C15-L354C25) says RT_TABLE_MAX=0xFFFFFFFF

Signed-off-by: Marcel Fest <marcel.fest@telekom.de>

* Better error handling for int check

Signed-off-by: Marcel Fest <marcel.fest@telekom.de>

* Better error message + typo fix

Signed-off-by: Marcel Fest <marcel.fest@telekom.de>

* Use MaxInt instead of MaxUint

Signed-off-by: Marcel Fest <marcel.fest@telekom.de>

---------

Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2024-06-26 12:29:07 +02:00
Daniel Finneran
9abce4a215 Update Makefile 2024-06-21 15:31:03 +01:00
Daniel Finneran
0b33aa64fc Merge pull request #884 from thebsdbox/go_security
bump golang for security fix
2024-06-21 15:30:47 +01:00
Dan Finneran
57980bd23f bump golang for security fix
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-06-21 14:18:58 +00:00
Daniel Finneran
69f4c389c5 Merge pull request #883 from thebsdbox/prometheus_fix
This allows prometheus configuration to be specified in the cli
2024-06-21 15:18:28 +01:00
Dan Finneran
f56c9b7480 This allows prometheus configuration to be specified in the cli
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-06-21 13:47:14 +00:00
dependabot[bot]
f8af9c37af Bump github.com/stretchr/testify from 1.8.4 to 1.9.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.4 to 1.9.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.4...v1.9.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 02:59:36 +00:00
Daniel Finneran
c16f634cf7 Merge pull request #869 from kube-vip/dependabot/go_modules/github.com/osrg/gobgp/v3-3.27.0
Bump github.com/osrg/gobgp/v3 from 3.25.0 to 3.27.0
2024-06-05 11:06:15 +01:00
dependabot[bot]
5df534a1e7 Bump github.com/osrg/gobgp/v3 from 3.25.0 to 3.27.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.25.0 to 3.27.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.25.0...v3.27.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-04 13:20:19 +00:00
Daniel Finneran
ee535938b4 Merge pull request #861 from kube-vip/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.19.0
Bump github.com/onsi/ginkgo/v2 from 2.17.2 to 2.19.0
2024-06-04 14:19:14 +01:00
Daniel Finneran
0df8a0dff4 Merge pull request #862 from kube-vip/dependabot/docker/alpine-3.20.0
Bump alpine from 3.19.1 to 3.20.0
2024-06-04 14:17:22 +01:00
Daniel Finneran
0e2a10535b Merge pull request #860 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.16.0
Bump anchore/sbom-action from 0.15.11 to 0.16.0
2024-06-04 14:17:08 +01:00
Daniel Finneran
b5d9ede6f8 Merge pull request #855 from p-strusiewiczsurmacki-mobica/lbclass-filtering
New service class filtering behavior
2024-06-04 14:16:51 +01:00
Daniel Finneran
94bad6d53b Merge pull request #868 from murphp15/main
Small correction to docs on retryPeriod property
2024-06-04 14:16:38 +01:00
Paul Murphy
927bb95ead Update kube-vip.go 2024-06-04 13:33:20 +01:00
Paul Murphy
7b96ebc7d4 Update config_types.go 2024-06-04 12:34:41 +01:00
Paul Murphy
5b05f365f1 Update kube-vip.go 2024-06-04 12:33:19 +01:00
dependabot[bot]
cd3d8a592c Bump alpine from 3.19.1 to 3.20.0
Bumps alpine from 3.19.1 to 3.20.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 02:42:31 +00:00
dependabot[bot]
e69fadf19b Bump github.com/onsi/ginkgo/v2 from 2.17.2 to 2.19.0
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.17.2 to 2.19.0.
- [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/v2.17.2...v2.19.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 02:35:13 +00:00
dependabot[bot]
5ded2d7574 Bump anchore/sbom-action from 0.15.11 to 0.16.0
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.11 to 0.16.0.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.11...v0.16.0)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 02:12:43 +00:00
Marcel Fest
c683bb879e Merge pull request #854 from kube-vip/hotfix/route-deletion
[Hotfix] Routes get not deleted when kube-vip is running without LeaderElection/ServiceElection in Table Mode
2024-05-17 15:53:57 +02:00
Daniel Finneran
392583d460 Merge pull request #853 from M0NsTeRRR/main
feat: generate VIPCIDR if not value is set
2024-05-17 14:15:23 +01:00
Patryk Strusiewicz-Surmacki
abf49f2fa6 New service class filtering behavior
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-05-17 14:45:30 +02:00
Marcel Fest
25c2532e74 when in table mode we always want to clean routes
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2024-05-17 12:30:53 +02:00
Ludovic Ortega
28918e839f feat: generate VIPCIDR if not value is set
Signed-off-by: Ludovic Ortega <ludovic.ortega@adminafk.fr>
2024-05-16 22:42:53 +02:00
Daniel Finneran
1620e4c890 Merge pull request #846 from testwill/close_file
fix: close file
2024-05-16 09:19:24 +01:00
guoguangwu
c8bdf61a87 fix: close file
Signed-off-by: guoguangwu <guoguangwug@gmail.com>
2024-05-15 19:13:41 +08:00
Daniel Finneran
e9835aa981 Merge pull request #847 from kube-vip/dependabot/docker/golang-1.22.3-alpine3.18
Bump golang from 1.22.2-alpine3.18 to 1.22.3-alpine3.18
2024-05-15 11:59:21 +01:00
dependabot[bot]
ca3dad817d Bump golang from 1.22.2-alpine3.18 to 1.22.3-alpine3.18
Bumps golang from 1.22.2-alpine3.18 to 1.22.3-alpine3.18.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-13 02:39:51 +00:00
Daniel Finneran
cb29d7cb17 Merge pull request #840 from kube-vip/dependabot/go_modules/github.com/onsi/gomega-1.33.1
Bump github.com/onsi/gomega from 1.32.0 to 1.33.1
2024-05-09 08:49:20 +01:00
Daniel Finneran
0fa7cbdab8 Merge pull request #834 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.15.11
Bump anchore/sbom-action from 0.15.10 to 0.15.11
2024-05-09 08:49:08 +01:00
dependabot[bot]
0038c27fec Bump github.com/onsi/gomega from 1.32.0 to 1.33.1
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.32.0 to 1.33.1.
- [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.32.0...v1.33.1)

---
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>
2024-05-08 14:01:32 +00:00
Daniel Finneran
4c19a3370c Merge pull request #826 from kube-vip/dependabot/go_modules/github.com/prometheus/client_golang-1.19.0
Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.0
2024-05-08 14:59:30 +01:00
Daniel Finneran
25abee70cd Merge pull request #833 from kube-vip/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.17.2
Bump github.com/onsi/ginkgo/v2 from 2.15.0 to 2.17.2
2024-05-08 14:58:37 +01:00
Daniel Finneran
057a32d191 Merge pull request #838 from p-strusiewiczsurmacki-mobica/route-deletion-fix
Fixed route deletion when route is used by more than one service
2024-05-08 14:58:21 +01:00
Daniel Finneran
b33a7b6d32 Merge pull request #837 from starbops/fix-835
fix: set service's uid in activeService map for inactive services
2024-05-08 14:57:58 +01:00
Patryk Strusiewicz-Surmacki
ba0c9282e7 Fixed route deletion when route is used by more than one service
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-04-30 14:44:26 +02:00
Zespre Schmidt
a431daab42 fix: set service's uid in activeService map for inactive services
Signed-off-by: Zespre Schmidt <starbops@zespre.com>
2024-04-30 16:31:10 +08:00
dependabot[bot]
54e4334b9f Bump anchore/sbom-action from 0.15.10 to 0.15.11
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.10 to 0.15.11.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.10...v0.15.11)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 02:55:01 +00:00
dependabot[bot]
6545a5aaab Bump github.com/onsi/ginkgo/v2 from 2.15.0 to 2.17.2
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.15.0 to 2.17.2.
- [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/v2.15.0...v2.17.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 02:13:32 +00:00
Daniel Finneran
2872256a89 Merge pull request #832 from ShivanshVij/main
fix: unecessary string modification
2024-04-25 08:26:35 +01:00
Shivansh Vij
a1ae304d07 fix: unecessary string modification
Signed-off-by: Shivansh Vij <shivanshvij@loopholelabs.io>
2024-04-24 12:32:27 -07:00
dependabot[bot]
c90d2043f0 Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.18.0 to 1.19.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.18.0...v1.19.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-22 02:47:11 +00:00
Daniel Finneran
722c47fc08 Update Makefile 2024-04-18 18:11:51 +01:00
Daniel Finneran
27fae664fe Merge pull request #821 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.13
Bump go.etcd.io/etcd/client/v3 from 3.5.11 to 3.5.13
2024-04-18 15:12:18 +01:00
Daniel Finneran
7349576e5b Merge pull request #820 from thebsdbox/bgp_err
Errors are being ignored
2024-04-18 14:59:08 +01:00
dependabot[bot]
1ab5047941 Bump go.etcd.io/etcd/client/v3 from 3.5.11 to 3.5.13
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.11 to 3.5.13.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.11...v3.5.13)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-18 13:52:10 +00:00
Dan Finneran
950264e403 lint fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-04-18 13:44:08 +00:00
Dan Finneran
0686b92376 Errors are being ignored
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-04-18 13:38:38 +00:00
Daniel Finneran
b7ebb21dc0 Merge pull request #796 from kube-vip/dependabot/go_modules/github.com/onsi/gomega-1.32.0
Bump github.com/onsi/gomega from 1.30.0 to 1.32.0
2024-04-18 14:22:50 +01:00
Daniel Finneran
ab904e2e18 Merge pull request #819 from thebsdbox/example
Examples and fixes to annotation interface
2024-04-18 14:22:37 +01:00
Dan Finneran
a5d4d0ca98 Examples and fixes to annotation interface
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-04-18 13:02:21 +00:00
dependabot[bot]
7fb301d3b3 Bump github.com/onsi/gomega from 1.30.0 to 1.32.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.30.0 to 1.32.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.30.0...v1.32.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>
2024-04-18 10:01:12 +00:00
Daniel Finneran
aa4da2f72a Merge pull request #816 from thebsdbox/interface_annotation
Adds annotation support for service interfaces.
2024-04-18 11:00:33 +01:00
Daniel Finneran
5dc91e6b3b Merge pull request #806 from kube-vip/dependabot/go_modules/github.com/osrg/gobgp/v3-3.25.0
Bump github.com/osrg/gobgp/v3 from 3.22.0 to 3.25.0
2024-04-18 10:58:29 +01:00
dependabot[bot]
658ca8697e Bump github.com/osrg/gobgp/v3 from 3.22.0 to 3.25.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.22.0 to 3.25.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.22.0...v3.25.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-18 09:47:41 +00:00
Daniel Finneran
979c016d98 Merge pull request #817 from thebsdbox/linting
fixes to linting
2024-04-18 10:45:32 +01:00
Dan Finneran
8e4abea78e fixes to linting
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-04-18 09:35:04 +00:00
Daniel Finneran
3caedde7fe Merge pull request #801 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.15.10
Bump anchore/sbom-action from 0.15.8 to 0.15.10
2024-04-18 10:24:13 +01:00
Daniel Finneran
fb43a48a87 Merge pull request #792 from kube-vip/dependabot/go_modules/k8s.io/apimachinery-0.29.3
Bump k8s.io/apimachinery from 0.29.1 to 0.29.3
2024-04-18 10:23:50 +01:00
Daniel Finneran
12e298bb22 Merge pull request #807 from kube-vip/dependabot/docker/golang-1.22.2-alpine3.18
Bump golang from 1.22.0-alpine3.18 to 1.22.2-alpine3.18
2024-04-18 10:23:32 +01:00
Daniel Finneran
f514269408 Merge pull request #778 from thebsdbox/remove_start
Removal of deprecated start command
2024-04-18 10:22:55 +01:00
Daniel Finneran
2c5d366487 Merge pull request #770 from lubronzhan/topic/lubron/fix-589
Mirror traffic of service interface to a dest interface
2024-04-18 10:22:32 +01:00
Daniel Finneran
fea05fa3ad Merge branch 'main' into topic/lubron/fix-589 2024-04-18 10:10:23 +01:00
Dan Finneran
5c515f0c0d Adds annotation support for service interfaces.
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-04-18 08:56:36 +00:00
Daniel Finneran
b0acf844ca Merge pull request #812 from wyike/fix_masquerade_issues
Fixes on masquerade forwarding mode
2024-04-18 09:54:11 +01:00
Daniel Finneran
bd3df6b616 Merge pull request #811 from d-uzlov/fix-nodename
Use node name for service election and lease holder name instead of hostname
2024-04-17 15:32:16 +01:00
Yike Wang
5100cd0e9a Fixes on masquerade forwarding mode
Signed-off-by: Yike Wang <yikew@vmware.com>
2024-04-17 08:59:44 +08:00
Danil Uzlov
04d863310b improve readability
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-11 03:35:02 +07:00
Danil Uzlov
29713acfeb fix golangci-lint better
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-11 03:32:49 +07:00
Danil Uzlov
8d607b89be fix golangci-lint
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-11 03:27:33 +07:00
Danil Uzlov
877ee75e75 go fmt
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-11 03:20:54 +07:00
Danil Uzlov
d3da4d934a check node names in services test
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-11 02:04:41 +07:00
Debian
c3e9a13f1c add hostname e2e test
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-11 02:04:36 +07:00
Danil Uzlov
59ad5ec9a2 fix e2e tests
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-10 21:28:09 +07:00
Danil Uzlov
8a80a72d94 fix golangci-lint
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-10 18:21:15 +07:00
Danil Uzlov
cb1e63c302 fix unit tests
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-10 17:58:20 +07:00
Danil Uzlov
e87ef6b3b8 go fmt
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-10 17:44:58 +07:00
Danil Uzlov
f87665c67f add fallback for hostname when node name is not available
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-10 17:43:53 +07:00
Daniel Finneran
c9d11e7123 Merge pull request #795 from adavis10006/fix-ddns
fix: add ddns address as a network
2024-04-10 09:59:55 +01:00
Daniel Finneran
51512201ea Merge pull request #809 from starbops/iptables-legacy
fix: add iptables-legacy package
2024-04-10 09:59:25 +01:00
Danil Uzlov
e37091c900 use node name instead of hostname
Signed-off-by: Danil Uzlov <36223296+d-uzlov@users.noreply.github.com>
2024-04-09 18:37:11 +07:00
Zespre Schmidt
b484be799e fix: add iptables-legacy package
Signed-off-by: Zespre Schmidt <starbops@zespre.com>
2024-04-08 15:21:56 +08:00
Shang-Kuei, Chen
2134c6b1fe fix: add ddns address as a network
Signed-off-by: Shang-Kuei, Chen <adavis10006@gmail.com>
2024-04-08 14:37:16 +08:00
dependabot[bot]
fbc6904fa0 Bump golang from 1.22.0-alpine3.18 to 1.22.2-alpine3.18
Bumps golang from 1.22.0-alpine3.18 to 1.22.2-alpine3.18.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 02:41:21 +00:00
Marcel Fest
0cedf6a97d Merge pull request #805 from Bao0ne/offline
fix: Modify the ImagePullPolicy used by cli manifest
2024-04-07 11:50:42 +02:00
wang
932fe09870 fix: Modify the ImagePullPolicy used by cli manifest
Signed-off-by: wang <wanglei@tdology.com>
2024-04-06 17:11:01 +08:00
Daniel Finneran
f1cf044eae Merge pull request #782 from lou-lan/fix/masquerade
Add masquerade mode
2024-04-02 11:06:22 +01:00
dependabot[bot]
a10a478f24 Bump anchore/sbom-action from 0.15.8 to 0.15.10
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.8 to 0.15.10.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.8...v0.15.10)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-01 02:11:42 +00:00
lou-lan
d1541c3464 Add masquerade mode
Signed-off-by: lou-lan <loulan@loulan.me>
2024-03-20 19:23:05 +08:00
dependabot[bot]
4e3717f089 Bump k8s.io/apimachinery from 0.29.1 to 0.29.3
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.29.1 to 0.29.3.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.29.1...v0.29.3)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-18 02:47:29 +00:00
Daniel Finneran
2aa799c9d0 Merge pull request #773 from kube-vip/dependabot/go_modules/go.uber.org/zap-1.27.0
Bump go.uber.org/zap from 1.26.0 to 1.27.0
2024-03-10 16:31:49 +00:00
Daniel Finneran
bb08489898 Merge pull request #783 from lubronzhan/topic/lubron/fix-781
Fix netmask of ipvs to consider ipv6 case
2024-03-10 16:30:49 +00:00
Daniel Finneran
1ea277f43e Merge pull request #777 from thebsdbox/egress_fix
Fixes conntrack deleting wrong connections and cleaning old SNAT rules
2024-03-10 16:23:45 +00:00
Daniel Finneran
2c4ff6949a Update Makefile for next release 2024-03-10 17:23:30 +01:00
lubronzhan
1a4bd01332 Refactor
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2024-03-10 09:13:16 -07:00
lubronzhan
9e2a13c133 Fix netmask of ipvs to consider ipv6 case
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2024-03-09 22:38:07 -08:00
Dan Finneran
39fbbc57ac linting fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-03-01 14:14:56 +00:00
Dan Finneran
b9f8c3b0f5 Removal of deprecated start command
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-03-01 12:29:05 +00:00
Daniel Finneran
ac5895a311 Merge pull request #775 from lubronzhan/topic/lubron/change_fatal
Exit(1) if service's leaderelection.onStartedLeading error out instead of silently continue
2024-03-01 11:05:44 +00:00
Daniel Finneran
e7eaa70fd4 Merge pull request #776 from lubronzhan/topic/lubron/fix-771
Fix flaky e2e test
2024-03-01 11:05:23 +00:00
Dan Finneran
76cf59c7a7 Fixes issues around conntrack deleting wrong connections and cleaning up old vip SNAT entries
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-03-01 10:54:50 +00:00
lubronzhan
a05ecbccb7 Consider 500 status code as a positive result of reaching control plane VIP
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2024-02-29 22:25:22 -08:00
lubronzhan
c531414542 Exit 1 if service's leaderelection onStartedLeading error out instead of silently continue
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2024-02-29 21:58:29 -08:00
lubronzhan
70b4728492 Resolve comments
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2024-02-29 21:48:20 -08:00
Lubron Zhan
835007b07a Refactor
Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>
2024-02-29 21:48:20 -08:00
Lubron Zhan
6d0c132519 Try clean up before deleting
Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>
2024-02-29 21:48:20 -08:00
Lubron Zhan
485cf6a0dd Fix the variable
Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>
2024-02-29 21:48:20 -08:00
Lubron Zhan
1338e4fcd3 Move mirroring traffic code to servicesWatcher
Signed-off-by: Lubron Zhan <lubronzhan@gmail.com>
2024-02-29 21:48:20 -08:00
lubronzhan
981355d910 Mirror traffic of service interface to a dest interface
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2024-02-29 21:48:20 -08:00
Daniel Finneran
3d5f1a6fa3 Update Makefile for new release 2024-02-26 09:45:58 +00:00
dependabot[bot]
e89d6f9f00 Bump go.uber.org/zap from 1.26.0 to 1.27.0
Bumps [go.uber.org/zap](https://github.com/uber-go/zap) from 1.26.0 to 1.27.0.
- [Release notes](https://github.com/uber-go/zap/releases)
- [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/zap/compare/v1.26.0...v1.27.0)

---
updated-dependencies:
- dependency-name: go.uber.org/zap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 02:56:34 +00:00
Daniel Finneran
a5ec16e1e8 Merge pull request #768 from thebsdbox/egress_fix
fixes a bug that wouldn't return CIDRs for egress
2024-02-21 16:11:42 +00:00
Dan Finneran
8de44b9253 fixes a bug that wouldn't return CIDRs for egress
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-02-21 15:25:40 +00:00
Daniel Finneran
911d4c0796 Merge pull request #757 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/api/v3-3.5.12
Bump go.etcd.io/etcd/api/v3 from 3.5.11 to 3.5.12
2024-02-21 14:35:19 +00:00
Daniel Finneran
b370681de4 Merge pull request #759 from kube-vip/dependabot/go_modules/golang.org/x/sys-0.17.0
Bump golang.org/x/sys from 0.16.0 to 0.17.0
2024-02-21 14:34:48 +00:00
Daniel Finneran
9b63a6e77a Merge pull request #764 from kube-vip/dependabot/go_modules/sigs.k8s.io/kind-0.22.0
Bump sigs.k8s.io/kind from 0.20.0 to 0.22.0
2024-02-21 14:34:33 +00:00
Daniel Finneran
56d57e7fae Merge pull request #763 from p-strusiewiczsurmacki-mobica/clean-routes
Added possibility to remove redundant routes
2024-02-21 14:31:13 +00:00
Patryk Strusiewicz-Surmacki
ba061e4475 Add protocol to legacy routes
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-21 11:41:51 +01:00
Daniel Finneran
6ddd053bce Merge pull request #765 from lou-lan/fix/ipvs
Fix IPVS service error: netlink receive invalid argument
2024-02-20 09:13:52 +00:00
Patryk Strusiewicz-Surmacki
f12d340134 Fixed concurrent map writes issue
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-20 10:08:29 +01:00
Patryk Strusiewicz-Surmacki
262ce70310 Changed default port, fixed typo, added route clean enable flag
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-19 14:41:17 +01:00
Patryk Strusiewicz-Surmacki
cce895e071 Added possibility to remove redundant routes
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-19 14:41:17 +01:00
lou-lan
388b6ca27f Fix IPVS service error: netlink receive invalid argument
Signed-off-by: lou-lan <loulan@loulan.me>
2024-02-19 16:39:14 +08:00
dependabot[bot]
0d27273ded Bump sigs.k8s.io/kind from 0.20.0 to 0.22.0
Bumps [sigs.k8s.io/kind](https://github.com/kubernetes-sigs/kind) from 0.20.0 to 0.22.0.
- [Release notes](https://github.com/kubernetes-sigs/kind/releases)
- [Commits](https://github.com/kubernetes-sigs/kind/compare/v0.20.0...v0.22.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/kind
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 02:07:51 +00:00
Daniel Finneran
7b7746b55f Merge pull request #760 from kube-vip/dependabot/docker/golang-1.22.0-alpine3.18
Bump golang from 1.21.6-alpine3.18 to 1.22.0-alpine3.18
2024-02-15 17:13:28 +00:00
Daniel Finneran
b666a95961 Merge pull request #761 from p-strusiewiczsurmacki-mobica/endpoints-common
Added common endpoint provider interface and fixed route deletion iss…
2024-02-15 17:13:11 +00:00
Patryk Strusiewicz-Surmacki
3534116d70 Fixed BGP issues
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-14 17:30:37 +01:00
Patryk Strusiewicz-Surmacki
107464fa1a Changed exist error chack from syscall to os
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-13 16:32:51 +01:00
Patryk Strusiewicz-Surmacki
814bf3d18f Added common endpoint provider interface and fixed route deletion issues in routing table mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-02-13 16:14:13 +01:00
dependabot[bot]
6503d7bec5 Bump golang from 1.21.6-alpine3.18 to 1.22.0-alpine3.18
Bumps golang from 1.21.6-alpine3.18 to 1.22.0-alpine3.18.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 03:03:12 +00:00
dependabot[bot]
c5e00d8660 Bump golang.org/x/sys from 0.16.0 to 0.17.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.16.0 to 0.17.0.
- [Commits](https://github.com/golang/sys/compare/v0.16.0...v0.17.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>
2024-02-12 02:54:17 +00:00
dependabot[bot]
409e188469 Bump go.etcd.io/etcd/api/v3 from 3.5.11 to 3.5.12
Bumps [go.etcd.io/etcd/api/v3](https://github.com/etcd-io/etcd) from 3.5.11 to 3.5.12.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.11...v3.5.12)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/api/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 02:54:07 +00:00
Daniel Finneran
8ccfdeca05 Merge pull request #750 from Wielewout/gen-manifests
fix: print manifests to stdout
2024-02-06 19:53:41 +01:00
Wout Van De Wiel
f933079da0 fix: print manifests to stdout
Signed-off-by: Wout Van De Wiel <wout.vandewiel@accelleran.com>
2024-02-06 18:42:01 +01:00
Daniel Finneran
b64243a3da Update ci.yaml
fixes issue with file descriptors
2024-02-06 11:01:44 +01:00
Daniel Finneran
d277c0ff23 Merge pull request #737 from kube-vip/dependabot/go_modules/k8s.io/client-go-0.29.1
Bump k8s.io/client-go from 0.29.0 to 0.29.1
2024-02-06 09:45:27 +01:00
dependabot[bot]
e9d2542c46 Bump k8s.io/client-go from 0.29.0 to 0.29.1
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.29.0 to 0.29.1.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.29.0...v0.29.1)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-06 08:36:33 +00:00
Daniel Finneran
57445329f1 Merge pull request #747 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.15.8
Bump anchore/sbom-action from 0.15.3 to 0.15.8
2024-02-06 09:36:00 +01:00
Daniel Finneran
66b224ed79 Merge pull request #736 from kube-vip/dependabot/go_modules/k8s.io/apimachinery-0.29.1
Bump k8s.io/apimachinery from 0.29.0 to 0.29.1
2024-02-06 09:35:42 +01:00
Daniel Finneran
67fbfe8973 Merge pull request #727 from kube-vip/dependabot/docker/golang-1.21.6-alpine3.18
Bump golang from 1.21.5-alpine3.18 to 1.21.6-alpine3.18
2024-02-06 09:31:37 +01:00
dependabot[bot]
55c6e6418f Bump k8s.io/apimachinery from 0.29.0 to 0.29.1
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.29.0 to 0.29.1.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.29.0...v0.29.1)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-06 08:24:47 +00:00
Daniel Finneran
d1ef0f443f Merge pull request #742 from kube-vip/dependabot/docker/alpine-3.19.1
Bump alpine from 3.19.0 to 3.19.1
2024-02-06 09:23:41 +01:00
Daniel Finneran
495bde2668 Merge pull request #735 from kube-vip/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.15.0
Bump github.com/onsi/ginkgo/v2 from 2.13.2 to 2.15.0
2024-02-06 09:23:26 +01:00
Daniel Finneran
01b889bfce Merge pull request #734 from kube-vip/dependabot/go_modules/k8s.io/klog/v2-2.120.1
Bump k8s.io/klog/v2 from 2.120.0 to 2.120.1
2024-02-06 09:23:04 +01:00
Daniel Finneran
a337127fc4 Merge pull request #746 from ii2day/pr/ii2day/format-log
fix: Using log instead of fmt.print
2024-02-06 09:22:00 +01:00
dependabot[bot]
c994b09f27 Bump anchore/sbom-action from 0.15.3 to 0.15.8
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.3 to 0.15.8.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.3...v0.15.8)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-05 02:55:11 +00:00
ii2day
7a93f6fd04 fix: Using log instead of fmt.print
Signed-off-by: ii2day <ii2day.zoro@gmail.com>
2024-02-05 09:58:32 +08:00
Daniel Finneran
34a4352fae Merge pull request #740 from p-strusiewiczsurmacki-mobica/no-leader-election-bgp
No-leader-election mode for BGP and fixes for routing table mode
2024-02-02 12:39:42 +01:00
Patryk Strusiewicz-Surmacki
e6e2e2b0a0 Fixed typo
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-31 11:40:09 +01:00
dependabot[bot]
fe9b669fc3 Bump alpine from 3.19.0 to 3.19.1
Bumps alpine from 3.19.0 to 3.19.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 02:19:46 +00:00
Patryk Strusiewicz-Surmacki
947c7bc8c0 Increased http test timeout
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-25 18:41:14 +01:00
Patryk Strusiewicz-Surmacki
fa1b2c965a No-leader-election mode for BGP and fixes for routing table mode
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-24 18:25:36 +01:00
dependabot[bot]
e85d8cd6c7 Bump github.com/onsi/ginkgo/v2 from 2.13.2 to 2.15.0
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.2 to 2.15.0.
- [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/v2.13.2...v2.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 02:09:10 +00:00
dependabot[bot]
deb0afb3a3 Bump k8s.io/klog/v2 from 2.120.0 to 2.120.1
Bumps [k8s.io/klog/v2](https://github.com/kubernetes/klog) from 2.120.0 to 2.120.1.
- [Release notes](https://github.com/kubernetes/klog/releases)
- [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes/klog/compare/v2.120.0...v2.120.1)

---
updated-dependencies:
- dependency-name: k8s.io/klog/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 02:09:00 +00:00
Daniel Finneran
cb2ae0a2b6 Merge pull request #725 from kube-vip/dependabot/go_modules/k8s.io/klog/v2-2.120.0
Bump k8s.io/klog/v2 from 2.110.1 to 2.120.0
2024-01-18 13:47:58 +00:00
Daniel Finneran
9bc4489ebc Merge pull request #718 from kube-vip/dependabot/go_modules/github.com/prometheus/client_golang-1.18.0
Bump github.com/prometheus/client_golang from 1.17.0 to 1.18.0
2024-01-18 13:47:39 +00:00
Daniel Finneran
6329cd0536 Merge pull request #717 from kube-vip/dependabot/go_modules/github.com/osrg/gobgp/v3-3.22.0
Bump github.com/osrg/gobgp/v3 from 3.19.0 to 3.22.0
2024-01-18 13:47:20 +00:00
Daniel Finneran
fe41b06277 Merge pull request #733 from thebsdbox/bgp_log_fix
Consistent logging
2024-01-18 13:46:54 +00:00
Dan Finneran
2e39d510e4 Consistent logging
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-18 12:47:08 +00:00
dependabot[bot]
1c4c11098e Bump github.com/osrg/gobgp/v3 from 3.19.0 to 3.22.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.19.0 to 3.22.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.19.0...v3.22.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-18 12:44:21 +00:00
dependabot[bot]
bbb0c86812 Bump github.com/prometheus/client_golang from 1.17.0 to 1.18.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.17.0...v1.18.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-18 12:43:50 +00:00
Daniel Finneran
3d100662d5 Merge pull request #716 from kube-vip/dependabot/go_modules/golang.org/x/sys-0.16.0
Bump golang.org/x/sys from 0.15.0 to 0.16.0
2024-01-18 12:43:21 +00:00
Daniel Finneran
6b6ebdcafa Merge pull request #726 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.15.3
Bump anchore/sbom-action from 0.15.1 to 0.15.3
2024-01-18 12:42:55 +00:00
Daniel Finneran
2b8d62279c Merge pull request #715 from kube-vip/dependabot/go_modules/github.com/packethost/packngo-0.31.0
Bump github.com/packethost/packngo from 0.30.0 to 0.31.0
2024-01-18 12:42:40 +00:00
Daniel Finneran
81f94fac36 Merge pull request #722 from p-strusiewiczsurmacki-mobica/dualstack-support
Minimal implementation of DualStack Services support
2024-01-18 09:37:56 +00:00
Daniel Finneran
dae044a2ab Merge pull request #730 from Cellebyte/fix/bgp
Added cli-options for bgp holdtime and keepalive
2024-01-16 13:22:02 +00:00
Marcel Fest
bb2c03335f Added cli-options for the bgp holdtime and keepalive
Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
2024-01-16 14:05:42 +01:00
Patryk Strusiewicz-Surmacki
eff0d21820 Fixed typo
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-16 13:31:39 +01:00
Patryk Strusiewicz-Surmacki
8ced01382f Reintroduced e2e test changes
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-15 21:41:17 +01:00
Patryk Strusiewicz-Surmacki
3d559ba0ce Minimal implementation of DualStack Services support
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-15 21:27:58 +01:00
Daniel Finneran
a2129b04df Merge pull request #720 from p-strusiewiczsurmacki-mobica/endpointslices-support
Non-leader-election for routing table mode
2024-01-15 15:16:54 +00:00
dependabot[bot]
c3209d5c17 Bump golang from 1.21.5-alpine3.18 to 1.21.6-alpine3.18
Bumps golang from 1.21.5-alpine3.18 to 1.21.6-alpine3.18.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 03:01:12 +00:00
dependabot[bot]
7f67c71582 Bump anchore/sbom-action from 0.15.1 to 0.15.3
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.1 to 0.15.3.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.1...v0.15.3)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 02:47:32 +00:00
dependabot[bot]
40508a4c6d Bump k8s.io/klog/v2 from 2.110.1 to 2.120.0
Bumps [k8s.io/klog/v2](https://github.com/kubernetes/klog) from 2.110.1 to 2.120.0.
- [Release notes](https://github.com/kubernetes/klog/releases)
- [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes/klog/compare/v2.110.1...v2.120.0)

---
updated-dependencies:
- dependency-name: k8s.io/klog/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 02:35:34 +00:00
Daniel Finneran
1dc52ed0d4 Merge pull request #724 from Cellebyte/fix/723
fix #723 and allow short hostnames as well
2024-01-13 19:10:30 +00:00
Cellebyte
29f7536083 fix #723 and allow short hostnames as well 2024-01-13 12:22:57 +01:00
Patryk Strusiewicz-Surmacki
d9fc6a5848 Fixed typos and removed error check after route deletion
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-12 13:27:00 +01:00
Patryk Strusiewicz-Surmacki
70a436ddf3 Improved logging. Fixed issue with endpointslices deletion event.
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-12 11:09:19 +01:00
Patryk Strusiewicz-Surmacki
9d640c5c44 Fixed linter issue
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-11 11:37:29 +01:00
Marcel Fest
7dda7b42c1 Added non-leader-election mode for routing table mode and preliminary support for endpointslices.
Signed-off-by: Patryk Strusiewicz-Surmacki <patryk-pawel.strusiewicz-surmacki@external.telekom.de>
2024-01-10 18:32:23 +01:00
dependabot[bot]
7dec367960 Bump golang.org/x/sys from 0.15.0 to 0.16.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.16.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>
2024-01-08 02:07:48 +00:00
dependabot[bot]
444b4a9c0d Bump github.com/packethost/packngo from 0.30.0 to 0.31.0
Bumps [github.com/packethost/packngo](https://github.com/packethost/packngo) from 0.30.0 to 0.31.0.
- [Release notes](https://github.com/packethost/packngo/releases)
- [Changelog](https://github.com/packethost/packngo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/packethost/packngo/compare/v0.30.0...v0.31.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 02:07:44 +00:00
Daniel Finneran
3c0e5e327e Update ci.yaml 2024-01-07 16:15:27 +00:00
Daniel Finneran
61d3d7ab45 Merge pull request #713 from thebsdbox/conf_path
Allows a configurable path to the kubernetes config
2024-01-07 15:45:59 +00:00
Dan Finneran
6ef860da52 Last fix
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-07 15:28:17 +00:00
Dan Finneran
748d60147d rage
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-07 15:13:15 +00:00
Dan Finneran
879b5337dc extensive fudging of the CI tests
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-07 15:04:13 +00:00
Dan Finneran
1aba51c70f v129 fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-07 14:38:08 +00:00
Dan Finneran
c60660d4d9 fix for IPv6
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-07 11:39:37 +00:00
Dan Finneran
6a7c198df0 remove lb step
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-07 11:24:43 +00:00
Dan Finneran
e0f9b195af grasping at straws
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-06 17:43:34 +00:00
Dan Finneran
80241ecc74 align timeouts
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-06 16:29:55 +00:00
Dan Finneran
047fe8f444 Additional tests
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-06 16:16:21 +00:00
Dan Finneran
d29b8d1bd8 Allows a configurable path to the kubernetes config
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-05 16:00:40 +00:00
Daniel Finneran
8fb2a7dc07 Merge pull request #712 from thebsdbox/build_nudge
Bumps the Makefile for a new release
2024-01-05 15:15:05 +00:00
Daniel Finneran
f5810f028f Merge pull request #700 from AHB102/master
Removed docs as described in Remove /docs #549
2024-01-05 14:02:10 +00:00
Dan Finneran
7901b8d50c Bumps the Makefile for a new release
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-05 14:00:49 +00:00
Daniel Finneran
c7b0a55718 Merge pull request #710 from thebsdbox/ipvs
fixes to the new ipvs import
2024-01-03 18:03:37 +00:00
Dan Finneran
98d6579d9d fixes to the new ipvs import
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-03 17:53:38 +00:00
Daniel Finneran
7dad075682 Merge pull request #660 from kube-vip/dependabot/go_modules/github.com/cloudflare/ipvs-0.10.1
Bump github.com/cloudflare/ipvs from 0.9.1 to 0.10.1
2024-01-03 17:48:07 +00:00
Daniel Finneran
eac6f6f75a Merge branch 'main' into dependabot/go_modules/github.com/cloudflare/ipvs-0.10.1 2024-01-03 17:48:01 +00:00
Daniel Finneran
0c98c1e28a Merge pull request #648 from amragaey/patch-1
#647 Update Dependencies for Security Patch
2024-01-03 15:13:16 +00:00
Daniel Finneran
5b00d30966 Merge branch 'main' into patch-1 2024-01-03 15:12:58 +00:00
Daniel Finneran
29ddbbbe04 Merge pull request #709 from thebsdbox/linter_actions_fix
More fixes
2024-01-03 15:12:18 +00:00
Dan Finneran
03467dd085 More fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-03 14:26:47 +00:00
Daniel Finneran
fc00d19271 Merge pull request #704 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.11
Bump go.etcd.io/etcd/client/v3 from 3.5.10 to 3.5.11
2024-01-03 14:15:40 +00:00
Daniel Finneran
3500d84fed Merge branch 'main' into dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.11 2024-01-03 14:15:29 +00:00
Daniel Finneran
09ab08b0ae Merge pull request #702 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/api/v3-3.5.11
Bump go.etcd.io/etcd/api/v3 from 3.5.10 to 3.5.11
2024-01-03 14:14:43 +00:00
Daniel Finneran
0fa5e96037 Merge pull request #703 from kube-vip/dependabot/go_modules/k8s.io/client-go-0.29.0
Bump k8s.io/client-go from 0.28.3 to 0.29.0
2024-01-03 14:12:05 +00:00
Daniel Finneran
e6d56f7eb0 Update codeql-analysis.yml 2024-01-03 14:07:53 +00:00
Daniel Finneran
9b73b3c87b Merge pull request #708 from thebsdbox/workflow_fix
Workflow update for go 1.21
2024-01-03 13:57:03 +00:00
Dan Finneran
a342c75a65 Workflow update for go 1.21
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-03 13:56:43 +00:00
Daniel Finneran
377545e835 Merge pull request #707 from thebsdbox/apiserver_depbot_fix
fixes go modules
2024-01-03 13:52:41 +00:00
Dan Finneran
66c86e995b fixes go modules
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2024-01-03 13:52:13 +00:00
dependabot[bot]
52776f4a75 Bump k8s.io/client-go from 0.28.3 to 0.29.0
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.28.3 to 0.29.0.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.28.3...v0.29.0)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-03 13:51:16 +00:00
dependabot[bot]
f82b4a08b4 Bump go.etcd.io/etcd/client/v3 from 3.5.10 to 3.5.11
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.10 to 3.5.11.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.10...v3.5.11)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-03 13:50:51 +00:00
dependabot[bot]
ec1288074e Bump go.etcd.io/etcd/api/v3 from 3.5.10 to 3.5.11
Bumps [go.etcd.io/etcd/api/v3](https://github.com/etcd-io/etcd) from 3.5.10 to 3.5.11.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.10...v3.5.11)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/api/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-03 13:50:18 +00:00
Daniel Finneran
a388fdf156 Merge pull request #688 from kube-vip/dependabot/go_modules/k8s.io/apimachinery-0.29.0
Bump k8s.io/apimachinery from 0.28.3 to 0.29.0
2024-01-03 13:49:16 +00:00
dependabot[bot]
0212e78dc6 Bump k8s.io/apimachinery from 0.28.3 to 0.29.0
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.28.3 to 0.29.0.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.28.3...v0.29.0)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-03 13:45:25 +00:00
Archit H Barve
12638aee85 Removed docs 2023-12-29 15:46:54 +05:30
Daniel Finneran
55a40bf771 Merge pull request #696 from zifeo/main
docs: fix directroute forwarding method
2023-12-28 16:31:01 +00:00
Daniel Finneran
3a7c331061 Merge pull request #673 from kube-vip/dependabot/go_modules/k8s.io/api-0.28.4
Bump k8s.io/api from 0.28.3 to 0.28.4
2023-12-28 16:28:45 +00:00
Daniel Finneran
35077570ff Merge branch 'main' into dependabot/go_modules/k8s.io/api-0.28.4 2023-12-28 16:28:34 +00:00
Daniel Finneran
24e3780792 Merge pull request #690 from kube-vip/dependabot/go_modules/golang.org/x/crypto-0.17.0
Bump golang.org/x/crypto from 0.14.0 to 0.17.0
2023-12-28 16:27:35 +00:00
Daniel Finneran
c7c772e40d Merge pull request #697 from kube-vip/dependabot/go_modules/github.com/spf13/cobra-1.8.0
Bump github.com/spf13/cobra from 1.7.0 to 1.8.0
2023-12-28 16:27:20 +00:00
Daniel Finneran
2d498d9161 Merge pull request #699 from thebsdbox/k8s_client
Updates to the client to auto-detect
2023-12-28 15:29:12 +00:00
Dan Finneran
52ad35d462 disable local tests
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-28 14:24:44 +00:00
Dan Finneran
2cfe326b9c Updates to the client to auto-detect
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-28 14:19:35 +00:00
dependabot[bot]
5308dfc055 Bump github.com/spf13/cobra from 1.7.0 to 1.8.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-25 02:22:51 +00:00
Teo Stocco
4438fcb6d3 docs: fix directroute forwarding method 2023-12-24 15:33:39 +01:00
dependabot[bot]
88dbd0f45d Bump golang.org/x/crypto from 0.14.0 to 0.17.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-22 12:25:40 +00:00
Daniel Finneran
69306d471c Merge pull request #672 from kube-vip/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.13.2
Bump github.com/onsi/ginkgo/v2 from 2.13.0 to 2.13.2
2023-12-22 12:24:29 +00:00
Daniel Finneran
82e7399f60 Merge pull request #680 from kube-vip/dependabot/docker/golang-1.21.5-alpine3.18
Bump golang from 1.21.4-alpine3.18 to 1.21.5-alpine3.18
2023-12-22 12:23:13 +00:00
Daniel Finneran
0215a0e39e Merge pull request #678 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.15.1
Bump anchore/sbom-action from 0.15.0 to 0.15.1
2023-12-22 12:22:56 +00:00
Daniel Finneran
2190a91df7 Merge pull request #689 from kube-vip/dependabot/github_actions/github/codeql-action-3
Bump github/codeql-action from 2 to 3
2023-12-22 12:22:40 +00:00
Daniel Finneran
17a07e6e4c Merge pull request #679 from kube-vip/dependabot/github_actions/actions/setup-go-5
Bump actions/setup-go from 4 to 5
2023-12-22 12:22:28 +00:00
Daniel Finneran
93fe008cc6 Merge pull request #674 from kube-vip/dependabot/go_modules/github.com/prometheus/client_golang-1.17.0
Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0
2023-12-22 12:22:05 +00:00
Daniel Finneran
eb880a2885 Merge pull request #681 from kube-vip/dependabot/docker/alpine-3.19.0
Bump alpine from 3.18.4 to 3.19.0
2023-12-22 08:03:48 +00:00
Daniel Finneran
dbf3233250 Merge pull request #695 from marc-cerebras/marc-cerebras/bgp-timer-cfg
Add config options for BGP timers
2023-12-22 08:03:24 +00:00
Daniel Finneran
2123ecf9c0 Merge pull request #687 from flawedmatrix/handle-dualstack-lb-ips
Dualstack support for Loadbalancer Services
2023-12-22 08:02:33 +00:00
marc-cerebras
06285210d0 update tests 2023-12-21 14:58:37 -08:00
marc-cerebras
fb062f7a55 add overlay for annotation driven cfg 2023-12-21 14:36:07 -08:00
marc-cerebras
5b63e4a181 add cfg opts for bgp timers 2023-12-21 12:56:01 -08:00
Daniel Finneran
0ae3ff840c Merge pull request #693 from thebsdbox/k8s_e2e
Adds capability to use your own images for e2e
2023-12-20 16:18:31 +00:00
Dan Finneran
20b3a3c00b Adds capability to use your own images for e2e
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-20 16:07:53 +00:00
Edwin Xie
e22ee4de74 Add service test for dualstack LB services
Signed-off-by: Edwin Xie <exie@vmware.com>
2023-12-19 18:55:04 +00:00
Edwin Xie
d21ce886a2 Preliminary support for dualstack loadbalancer services
Signed-off-by: Edwin Xie <exie@vmware.com>
2023-12-19 18:54:56 +00:00
dependabot[bot]
9c79e88ccb Bump github/codeql-action from 2 to 3
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 02:19:34 +00:00
dependabot[bot]
079423f218 Bump k8s.io/api from 0.28.3 to 0.28.4
Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.28.3 to 0.28.4.
- [Commits](https://github.com/kubernetes/api/compare/v0.28.3...v0.28.4)

---
updated-dependencies:
- dependency-name: k8s.io/api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-12 16:09:01 +00:00
dependabot[bot]
dfd8b38268 Bump github.com/onsi/ginkgo/v2 from 2.13.0 to 2.13.2
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.0 to 2.13.2.
- [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/v2.13.0...v2.13.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-12 16:07:59 +00:00
Daniel Finneran
c03b7edb5f Merge pull request #671 from kube-vip/dependabot/go_modules/golang.org/x/sys-0.15.0
Bump golang.org/x/sys from 0.13.0 to 0.15.0
2023-12-12 16:06:51 +00:00
dependabot[bot]
be404237bd Bump alpine from 3.18.4 to 3.19.0
Bumps alpine from 3.18.4 to 3.19.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 02:36:33 +00:00
dependabot[bot]
5b48797f8a Bump golang from 1.21.4-alpine3.18 to 1.21.5-alpine3.18
Bumps golang from 1.21.4-alpine3.18 to 1.21.5-alpine3.18.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 02:36:30 +00:00
dependabot[bot]
b0c344298c Bump actions/setup-go from 4 to 5
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v5)

---
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-12-11 02:31:01 +00:00
dependabot[bot]
c79fff8d86 Bump anchore/sbom-action from 0.15.0 to 0.15.1
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.0 to 0.15.1.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.15.0...v0.15.1)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 02:30:58 +00:00
dependabot[bot]
b72ae63060 Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.16.0...v1.17.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-04 02:35:08 +00:00
dependabot[bot]
9835fd4410 Bump golang.org/x/sys from 0.13.0 to 0.15.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.13.0 to 0.15.0.
- [Commits](https://github.com/golang/sys/compare/v0.13.0...v0.15.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-12-04 02:34:43 +00:00
Daniel Finneran
6a642c788a Merge pull request #670 from thebsdbox/lint_fix_routing
Fixes to linting for routing table
2023-12-03 10:38:40 +00:00
Daniel Finneran
47924247c4 Merge pull request #607 from hellt/patch-1
Added create rbac settings section for kind deployment
2023-12-03 10:36:40 +00:00
dependabot[bot]
100da0a3a5 Bump github.com/cloudflare/ipvs from 0.9.1 to 0.10.1
Bumps [github.com/cloudflare/ipvs](https://github.com/cloudflare/ipvs) from 0.9.1 to 0.10.1.
- [Release notes](https://github.com/cloudflare/ipvs/releases)
- [Commits](https://github.com/cloudflare/ipvs/compare/v0.9.1...v0.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-03 10:35:14 +00:00
Daniel Finneran
945167cab4 Merge branch 'main' into patch-1 2023-12-03 10:33:53 +00:00
Dan Finneran
b0f7aa1698 Fixes to linting for routing table
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-03 10:32:51 +00:00
Daniel Finneran
2cee4723d4 Merge pull request #606 from CopernicaMarketingSoftware/main
Add environment variable for routing table type
2023-12-03 10:27:37 +00:00
Daniel Finneran
f33a0b7481 Merge branch 'main' into main 2023-12-03 10:26:03 +00:00
Daniel Finneran
f54595d8f7 Merge pull request #669 from thebsdbox/cleanup
Cleanup
2023-12-02 17:56:24 +00:00
Dan Finneran
68c9e49480 linting fixes.
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-02 16:38:56 +00:00
Dan Finneran
cfa2e93c76 Further cleaning
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-02 16:32:30 +00:00
Dan Finneran
1f1c7fe819 Tidies up logging messages and redundant logic
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-12-02 16:32:12 +00:00
Daniel Finneran
c7abf75c17 Merge pull request #655 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.10
Bump go.etcd.io/etcd/client/v3 from 3.5.9 to 3.5.10
2023-12-02 16:10:09 +00:00
Daniel Finneran
befe2b92aa Merge branch 'main' into dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.10 2023-12-02 16:09:58 +00:00
Daniel Finneran
cd86f70a20 Merge pull request #661 from kube-vip/dependabot/go_modules/github.com/onsi/gomega-1.30.0
Bump github.com/onsi/gomega from 1.27.10 to 1.30.0
2023-12-02 16:08:55 +00:00
Daniel Finneran
0a4a1dc12d Merge pull request #659 from kube-vip/dependabot/docker/golang-1.21.4-alpine3.18
Bump golang from 1.21.3-alpine3.18 to 1.21.4-alpine3.18
2023-12-02 16:08:39 +00:00
Daniel Finneran
99dcf88cb2 Merge pull request #657 from kube-vip/dependabot/github_actions/docker/setup-buildx-action-3
Bump docker/setup-buildx-action from 1 to 3
2023-12-02 16:08:09 +00:00
Daniel Finneran
b53b340649 Merge pull request #668 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.15.0
Bump anchore/sbom-action from 0.14.3 to 0.15.0
2023-12-02 16:07:45 +00:00
Daniel Finneran
8d90a805b4 Merge pull request #656 from kube-vip/dependabot/github_actions/docker/login-action-3
Bump docker/login-action from 1 to 3
2023-12-02 16:07:08 +00:00
Daniel Finneran
0626053eb5 Merge pull request #654 from kube-vip/dependabot/go_modules/go.etcd.io/etcd/client/pkg/v3-3.5.10
Bump go.etcd.io/etcd/client/pkg/v3 from 3.5.9 to 3.5.10
2023-12-02 16:06:47 +00:00
Daniel Finneran
de7a454462 Merge pull request #653 from kube-vip/dependabot/go_modules/sigs.k8s.io/yaml-1.4.0
Bump sigs.k8s.io/yaml from 1.3.0 to 1.4.0
2023-12-02 16:06:31 +00:00
Daniel Finneran
247cffb006 Merge pull request #664 from shkuviak/feature/service-dhcp-hostname
Add annotation to specify DHCP lease hostname
2023-12-02 16:06:10 +00:00
dependabot[bot]
0f29b97dd4 Bump anchore/sbom-action from 0.14.3 to 0.15.0
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.14.3 to 0.15.0.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.14.3...v0.15.0)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-27 02:25:46 +00:00
Nicolas JENDROWIAK
e7b68cfd3a Add upgrade command in Dockerfile_iptables
Fix trivy warning on vulnerable libcrypto package
-> No newer alpine image on dockerhub

Signed-off-by: Nicolas JENDROWIAK <75165555+shkuviak@users.noreply.github.com>
2023-11-25 18:22:14 +01:00
Nicolas JENDROWIAK
08abd3812a Added trivy command in makefile
Signed-off-by: Nicolas JENDROWIAK <75165555+shkuviak@users.noreply.github.com>
2023-11-25 18:22:14 +01:00
Nicolas JENDROWIAK
f0de6767a3 lint
Signed-off-by: Nicolas JENDROWIAK <nico.jendrowiak@gmail.com>
2023-11-24 17:13:03 +01:00
Daniel Finneran
b42b78283c Merge pull request #650 from aarnaud/doc/k0sctl
Add doc for static pods on k0s using k0sctl
2023-11-21 17:06:11 -01:00
Daniel Finneran
a0fed6b166 Merge branch 'main' into patch-1 2023-11-19 08:24:45 +00:00
Nicolas JENDROWIAK
a295b44d83 [svc] Add annotation to specify DHCP lease host
Signed-off-by: Nicolas JENDROWIAK <nico.jendrowiak@gmail.com>
2023-11-16 12:16:09 +01:00
dependabot[bot]
259b31cef2 Bump github.com/onsi/gomega from 1.27.10 to 1.30.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.27.10 to 1.30.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.27.10...v1.30.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-11-13 02:36:55 +00:00
dependabot[bot]
16c8deb0fe Bump golang from 1.21.3-alpine3.18 to 1.21.4-alpine3.18
Bumps golang from 1.21.3-alpine3.18 to 1.21.4-alpine3.18.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-13 02:25:42 +00:00
dependabot[bot]
cf9fa5b30b Bump docker/setup-buildx-action from 1 to 3
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 02:59:03 +00:00
dependabot[bot]
334590b88c Bump docker/login-action from 1 to 3
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 02:58:58 +00:00
dependabot[bot]
f0987424ef Bump go.etcd.io/etcd/client/v3 from 3.5.9 to 3.5.10
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.9 to 3.5.10.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.9...v3.5.10)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 02:58:36 +00:00
dependabot[bot]
864bacfb13 Bump go.etcd.io/etcd/client/pkg/v3 from 3.5.9 to 3.5.10
Bumps [go.etcd.io/etcd/client/pkg/v3](https://github.com/etcd-io/etcd) from 3.5.9 to 3.5.10.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.9...v3.5.10)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/pkg/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 02:58:25 +00:00
dependabot[bot]
6e528fef90 Bump sigs.k8s.io/yaml from 1.3.0 to 1.4.0
Bumps [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/kubernetes-sigs/yaml/releases)
- [Changelog](https://github.com/kubernetes-sigs/yaml/blob/master/RELEASE.md)
- [Commits](https://github.com/kubernetes-sigs/yaml/compare/v1.3.0...v1.4.0)

---
updated-dependencies:
- dependency-name: sigs.k8s.io/yaml
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 02:58:13 +00:00
Anthony ARNAUD
14c27ff839 Add doc for static pods on k0s using k0sctl
Signed-off-by: Anthony ARNAUD <github@anthony-arnaud.fr>
2023-10-26 12:11:35 -04:00
Daniel Finneran
063cc2fb8d Merge pull request #643 from kube-vip/dependabot/go_modules/k8s.io/client-go-0.28.3
Bump k8s.io/client-go from 0.27.4 to 0.28.3
2023-10-26 12:06:20 +02:00
Daniel Finneran
f5091a4650 Merge pull request #640 from kube-vip/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 2 to 4
2023-10-26 12:06:07 +02:00
Daniel Finneran
7ea481b904 Merge pull request #637 from kube-vip/dependabot/docker/alpine-3.18.4
Bump alpine from 3.18.3 to 3.18.4
2023-10-26 12:05:51 +02:00
Daniel Finneran
9b7ef5db31 Merge pull request #649 from kube-vip/dependabot/go_modules/google.golang.org/grpc-1.57.1
Bump google.golang.org/grpc from 1.57.0 to 1.57.1
2023-10-26 12:05:09 +02:00
dependabot[bot]
a25cc92daa Bump k8s.io/client-go from 0.27.4 to 0.28.3
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.27.4 to 0.28.3.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.27.4...v0.28.3)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 09:51:15 +00:00
dependabot[bot]
08d71536e9 Bump google.golang.org/grpc from 1.57.0 to 1.57.1
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 09:51:00 +00:00
Daniel Finneran
256743758b Merge pull request #644 from kube-vip/dependabot/go_modules/github.com/osrg/gobgp/v3-3.19.0
Bump github.com/osrg/gobgp/v3 from 3.17.0 to 3.19.0
2023-10-26 11:49:10 +02:00
Daniel Finneran
b4593b2c9e Merge pull request #641 from kube-vip/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.13.0
Bump github.com/onsi/ginkgo/v2 from 2.12.1 to 2.13.0
2023-10-26 11:48:49 +02:00
Daniel Finneran
f024f5ebbc Merge pull request #645 from kube-vip/dependabot/go_modules/go.uber.org/zap-1.26.0
Bump go.uber.org/zap from 1.21.0 to 1.26.0
2023-10-26 11:48:27 +02:00
Daniel Finneran
b643453816 Merge pull request #639 from kube-vip/dependabot/github_actions/docker/build-push-action-5
Bump docker/build-push-action from 2 to 5
2023-10-26 11:48:09 +02:00
dependabot[bot]
1eb9bddb9c Bump alpine from 3.18.3 to 3.18.4
Bumps alpine from 3.18.3 to 3.18.4.

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 09:47:13 +00:00
Daniel Finneran
ace7001e91 Merge pull request #638 from kube-vip/dependabot/github_actions/anchore/sbom-action-0.14.3
Bump anchore/sbom-action from 0.12.0 to 0.14.3
2023-10-26 11:47:09 +02:00
dependabot[bot]
3ea0b629ac Bump actions/checkout from 2 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4.
- [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...v4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 09:46:42 +00:00
Daniel Finneran
fb9d80aaaa Merge pull request #636 from kube-vip/dependabot/github_actions/github/codeql-action-2
Bump github/codeql-action from 1 to 2
2023-10-26 11:45:56 +02:00
Daniel Finneran
ed0281b243 Merge pull request #635 from kube-vip/dependabot/github_actions/docker/setup-qemu-action-3
Bump docker/setup-qemu-action from 1 to 3
2023-10-26 11:45:45 +02:00
Daniel Finneran
4d7409f18f Merge pull request #634 from kube-vip/dependabot/docker/golang-1.21.3-alpine3.18
Bump golang from 1.20.8-alpine3.18 to 1.21.3-alpine3.18
2023-10-26 11:45:18 +02:00
Amr Ragaey
305572359d update go-restful version 2023-10-26 11:57:20 +03:00
Amr Ragaey
12ab991048 update Go version 2023-10-26 11:52:37 +03:00
dependabot[bot]
2a8e981b49 Bump go.uber.org/zap from 1.21.0 to 1.26.0
Bumps [go.uber.org/zap](https://github.com/uber-go/zap) from 1.21.0 to 1.26.0.
- [Release notes](https://github.com/uber-go/zap/releases)
- [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/zap/compare/v1.21.0...v1.26.0)

---
updated-dependencies:
- dependency-name: go.uber.org/zap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:34:02 +00:00
dependabot[bot]
1cde04e8a1 Bump github.com/osrg/gobgp/v3 from 3.17.0 to 3.19.0
Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.17.0 to 3.19.0.
- [Release notes](https://github.com/osrg/gobgp/releases)
- [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml)
- [Commits](https://github.com/osrg/gobgp/compare/v3.17.0...v3.19.0)

---
updated-dependencies:
- dependency-name: github.com/osrg/gobgp/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:33:46 +00:00
dependabot[bot]
52bacaa03c Bump github.com/onsi/ginkgo/v2 from 2.12.1 to 2.13.0
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.12.1 to 2.13.0.
- [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/v2.12.1...v2.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:31:39 +00:00
dependabot[bot]
4e88e32e56 Bump docker/build-push-action from 2 to 5
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 5.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v5)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:29:36 +00:00
dependabot[bot]
202274d4f1 Bump anchore/sbom-action from 0.12.0 to 0.14.3
Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.12.0 to 0.14.3.
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Commits](https://github.com/anchore/sbom-action/compare/v0.12.0...v0.14.3)

---
updated-dependencies:
- dependency-name: anchore/sbom-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:29:32 +00:00
dependabot[bot]
f20fa9df3e Bump github/codeql-action from 1 to 2
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:29:29 +00:00
dependabot[bot]
70e94d24f4 Bump docker/setup-qemu-action from 1 to 3
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:29:24 +00:00
dependabot[bot]
a8914af861 Bump golang from 1.20.8-alpine3.18 to 1.21.3-alpine3.18
Bumps golang from 1.20.8-alpine3.18 to 1.21.3-alpine3.18.

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 20:29:23 +00:00
Daniel Finneran
5a0715dc50 Merge pull request #633 from mrueg/dependabot 2023-10-23 22:29:03 +02:00
Manuel Rüger
31955fedf7 .github: Add a dependabot config
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2023-10-23 19:24:45 +02:00
Daniel Finneran
888eff1317 Merge pull request #628 from kube-vip/dependabot/go_modules/golang.org/x/net-0.17.0
Bump golang.org/x/net from 0.12.0 to 0.17.0
2023-10-17 11:28:44 +02:00
Daniel Finneran
29d7773064 Merge pull request #629 from g-gaston/fix-etcd-e2e-test-action
Fix etcd e2e tests in GitHub actions
2023-10-17 11:21:45 +02:00
Guillermo Gaston
b5bf507546 Fix etcd e2e tests in GitHub actions
In order to run the kubelet in kind containers on the vms provided by
github, the kubelet needed some extra configuration.

Signed-off-by: Guillermo Gaston <gaslor@amazon.com>
2023-10-17 00:23:49 +00:00
dependabot[bot]
04bdc57434 Bump golang.org/x/net from 0.12.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.12.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.12.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-14 11:20:58 +00:00
Daniel Finneran
fa26d779a0 Merge pull request #626 from g-gaston/etcd-vip
Add leader election using etcd as a backend
2023-10-14 13:19:56 +02:00
Guillermo Gaston
ae307f8cad Add leader election using etcd as a backend
This adds a new leader election mode that instead of using the kube api
server to obtain a lease, it relies solely on etcd.

By removing the dependency on the api server, we can use it even before
the api server is up, before cluster creation.

In an external etcd topology, this way we can make the api server point
to the VIPs instead of to the etcd machines IPs. This configuration
isolates the CP configuration from the etcd machine IPS. It's is super
convenient to avoid having to roll new control plane nodes when the etcd
nodes change.

Signed-off-by: Guillermo Gaston <gaslor@amazon.com>
2023-10-06 17:03:03 +00:00
Daniel Finneran
cbcc68e69d Update Makefile
Bump for new release
2023-10-04 09:37:41 +01:00
Daniel Finneran
a09a1db44c Merge pull request #623 from thebsdbox/fatal_interface
Call fatal when interface fails
2023-10-04 10:36:46 +02:00
Daniel Finneran
8d362d9d67 Merge pull request #624 from g-gaston/unit-tests
Enable unit and e2e tests in CI
2023-10-04 10:36:31 +02:00
Guillermo Gaston
72410cc6f7 Enable unit and e2e tests in CI
* Fix 2 broken tests
* Fix e2e ARP tests: killing one node in a 2 CP node cluster makes etcd
  lose quorum. So it can't elect a new leader if the node we happen to
  kill was the etcd leader.
* Separate unit tests, e2e tests, linter and scans in different jobs so
  they run concurrently.

Signed-off-by: Guillermo Gaston <gaslor@amazon.com>
2023-10-03 22:00:09 +00:00
Dan Finneran
36bccb723e Call fatal when interface fails
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-10-03 14:47:44 +00:00
Daniel Finneran
bfa6a9a9ac Merge pull request #622 from Willena/feat/svc-lock-configurable-in-arp-mode
Allow svc lock name to be configurable in arp mode.
2023-10-03 16:38:07 +02:00
Guillaume Villena
e41abf0f88 Allow svc lock name to be configurable in arp mode.
Signed-off-by: Guillaume Villena <guillaume@villena.me>
2023-10-01 01:12:37 +02:00
Daniel Finneran
0def3c0346 Merge pull request #621 from thebsdbox/endpoint_fqdn
Adds logic and debugging around fqdn endpoints
2023-09-29 17:02:56 +02:00
Dan Finneran
0ad1ccbf2f Adds logic and debugging around fqdn endpoints
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-09-28 12:38:54 +00:00
Daniel Finneran
219bc19bc2 Update ci.yaml
Adds Trivy scanning
2023-09-28 11:39:46 +01:00
Daniel Finneran
565e6dc550 Merge pull request #619 from thebsdbox/alpine_bump
This bumps the base images for vulnerabilities
2023-09-27 11:33:05 +02:00
Dan Finneran
d69a92f312 This bumps the base images for vulnerabilities
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-09-27 09:20:31 +00:00
Daniel Finneran
cc96d65b14 Merge pull request #612 from mjtrangoni/chore 2023-09-22 22:45:00 +02:00
Daniel Finneran
bad938105f Merge pull request #613 from mjtrangoni/handle-prom-root 2023-09-22 22:44:41 +02:00
Daniel Finneran
a826649886 Merge pull request #617 from mjtrangoni/add-node-labeling 2023-09-22 22:44:09 +02:00
Mario Trangoni
5ac633f319 ARP: Add node labeling for ARP mode DaemonSet deployment.
This feature is related to #611, to configure the
`CiliumEgressGatewayPolicy` EgressIP correctly.

As this is not a very common usage for this project, there is a default
disabled configuration flag added, `enable_node_labeling`.

Signed-off-by: Mario Trangoni <mjtrangoni@gmail.com>
2023-09-19 13:47:44 +02:00
Mario Trangoni
d8ed0e5296 prometheus: Handle root path
Signed-off-by: Mario Trangoni <mjtrangoni@gmail.com>
2023-09-14 14:26:01 +02:00
Mario Trangoni
06e41bae50 chore: Fix some misspellings found by codespell
Signed-off-by: Mario Trangoni <mjtrangoni@gmail.com>
2023-09-14 11:11:44 +02:00
Mario Trangoni
99e9579de5 Ignore kube-vip binary
Signed-off-by: Mario Trangoni <mjtrangoni@gmail.com>
2023-09-14 11:07:47 +02:00
Timo Sluis
31b7aad6c0 revert go.mod and go.sum
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-11 13:14:04 +02:00
Timo Sluis
991587c294 fix formatting + add route to link + remove route on shutdown
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-11 11:06:48 +02:00
Timo Sluis
89d883d0ec add routing table id as envvar
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-08 15:50:24 +02:00
Timo Sluis
724ec2ab10 specify different scope for local routes
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-08 15:28:45 +02:00
Timo Sluis
8afe5ca155 add comment about valid values
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-07 13:34:51 +02:00
Roman Dodin
6d47329f7c added create rbac settings section for kind 2023-09-04 20:47:56 +02:00
Timo Sluis
9fbe98c5d9 gofmt
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-04 16:45:47 +02:00
Timo Sluis
55398e6cfc add routing table type environment variable
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-09-04 16:35:09 +02:00
Daniel Finneran
f7666067a4 Update Makefile for new release 2023-08-24 09:01:16 +01:00
Daniel Finneran
a47e46ce84 Merge pull request #601 from usiegl00/main
Fix dos through checking for remaining services before releasing ip. …
2023-08-18 09:37:15 +01:00
usiegl00
9c84c56959 Fix formatting to pass lint.
Signed-off-by: usiegl00 <50933431+usiegl00@users.noreply.github.com>
2023-08-18 03:42:46 +09:00
usiegl00
b4f5554670 Fix dos through checking for remaining services before releasing ip. Fixes #600
Signed-off-by: usiegl00 <50933431+usiegl00@users.noreply.github.com>
2023-08-17 05:03:36 +09:00
Daniel Finneran
96541380b5 Merge pull request #599 from thebsdbox/codeql
action fix
2023-08-15 19:41:15 +01:00
Dan Finneran
92338ae74f action fix
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-15 18:40:47 +00:00
Daniel Finneran
4e69ada00c Merge pull request #598 from thebsdbox/fix_main
Fix to main
2023-08-15 19:26:20 +01:00
Dan Finneran
baba79e6ad Fix to main
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-15 18:16:58 +00:00
Daniel Finneran
cfdd5d1c42 Merge pull request #575 from megakid/patch-1
Increase client QPS to reduce clientside k8api throttling
2023-08-15 19:14:41 +01:00
Daniel Finneran
57c008b6da Merge pull request #595 from jkossis/update-makefile-0.6.1
Updating version in makefile
2023-08-15 18:01:56 +01:00
Daniel Finneran
778886e426 Merge pull request #597 from thebsdbox/watch_fix
This makes sure we check if a services is active
2023-08-15 18:01:17 +01:00
Daniel Finneran
203de87a85 Merge pull request #596 from thebsdbox/e2e-2-death
Some BIG OLDE e2e tests!
2023-08-15 18:00:31 +01:00
Dan Finneran
a18e26dbc3 more_lint
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-15 16:46:19 +00:00
Dan Finneran
bc63ed2ee5 lint fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-15 15:32:25 +00:00
Dan Finneran
6a71e264da This makes sure we check if a services is active
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-15 15:25:30 +00:00
Dan Finneran
aa9cb9a49b Some BIG OLDE e2e tests!
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-15 15:21:32 +00:00
James Connor
74f6785f34 Compilation fixes again 2023-08-15 15:24:20 +01:00
James Connor
7a5d80bf35 Merge branch 'kube-vip:main' into patch-1 2023-08-15 15:21:49 +01:00
Jason Kossis
5f9dc0a997 initial commit
Signed-off-by: Jason Kossis <jason.kossis@aexp.com>
2023-08-14 08:17:47 -04:00
Daniel Finneran
18fadf25a2 Merge pull request #593 from thebsdbox/ginko_bump
Fixes to ginko
2023-08-14 08:25:46 +01:00
Dan Finneran
92e13761e4 MORE AND MORE FIXES
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-13 15:04:39 +00:00
Dan Finneran
ab7ceb8933 more fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-13 14:45:16 +00:00
Dan Finneran
bac763e3f4 more tidying
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-13 14:04:33 +00:00
Dan Finneran
c2215e5d98 Fixes to ginko
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-13 13:57:12 +00:00
Daniel Finneran
c54994e9b7 Merge pull request #592 from thebsdbox/e2e_fixes
Fixes to e2e tests and re-enabling
2023-08-13 14:28:12 +01:00
Dan Finneran
1da54e6d8e lint fixes.
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-13 13:13:18 +00:00
Dan Finneran
9bfbb295dd Fixes to e2e tests and re-enabling
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-08-13 13:09:41 +00:00
Daniel Finneran
5a06a8888d Merge pull request #576 from mrueg/update-deps-0623
Update go dependencies
2023-08-12 10:27:30 +01:00
Manuel Rüger
7b64893703 Update golangci-lint
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2023-08-01 14:06:21 +02:00
Manuel Rüger
f36b433093 Update go dependencies
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2023-08-01 14:06:21 +02:00
Daniel Finneran
ec5a5139c8 Merge pull request #587 from rikatz/fix-dhcp-workflow-part1 2023-07-27 22:21:26 +01:00
Ricardo Katz
3d357a452b Fix linter error
Signed-off-by: Ricardo Katz <ricardo.katz@gmail.com>
2023-07-27 16:41:41 -03:00
Ricardo Katz
702a27bb1e Add proper backoff and max errors on dhcp client
Signed-off-by: Ricardo Katz <ricardo.katz@gmail.com>
2023-07-24 12:15:07 -03:00
Ricardo Katz
0060d36694 Update the DHCP workflows
Signed-off-by: Ricardo Katz <ricardo.katz@gmail.com>
2023-07-24 12:15:07 -03:00
Daniel Finneran
bdb9b0ef91 Merge pull request #585 from timosluis/lease_annotations
Allow specifying annotations for created Lease resources
2023-07-18 09:35:44 +01:00
Daniel Finneran
1ad0ae7740 Merge pull request #583 from kube-vip/dependabot/go_modules/google.golang.org/grpc-1.53.0
Bump google.golang.org/grpc from 1.51.0 to 1.53.0
2023-07-18 09:35:27 +01:00
Daniel Finneran
8c0791db19 Merge pull request #579 from runsisi/wip-fix-target
Fix makefile default target
2023-07-18 09:35:04 +01:00
Daniel Finneran
ec80533f81 Merge pull request #578 from marc-cerebras/marc-cerebras/bgp-cp-leaderelect
enable leaderelection for bgp in CP mode
2023-07-18 09:34:51 +01:00
Timo Sluis
64f8ebd865 fix formatting
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-07-12 11:27:49 +02:00
Timo Sluis
9667c7766f add lease annotations
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-07-12 11:14:14 +02:00
dependabot[bot]
23492519ed Bump google.golang.org/grpc from 1.51.0 to 1.53.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.51.0 to 1.53.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.51.0...v1.53.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 21:37:26 +00:00
runsisi
f2f7d362c7 Fix makefile default target
Signed-off-by: runsisi <runsisi@hust.edu.cn>
2023-06-21 07:53:43 +08:00
marc-cerebras
2dcd9e50c9 enable leaderelection for bgp in CP mode
Signed-off-by: marc-cerebras <marc.spehlmann@cerebras.net>
2023-06-19 11:25:13 -07:00
James Connor
c3ab677ad1 PR Fixes 2023-06-02 17:22:21 +01:00
James Connor
09daa0c57f Merge branch 'kube-vip:main' into patch-1 2023-06-02 17:20:04 +01:00
Daniel Finneran
c3a700ba3f Merge pull request #573 from timosluis/main
Use configurable LeaseName instead of hardcoded
2023-06-02 08:45:49 +01:00
James Connor
6f2acf0198 Increase client QPS to reduce clientside k8api throttling 2023-05-30 12:54:46 +01:00
Daniel Finneran
af86209d63 Merge pull request #571 from lubronzhan/topic/lubron/check_lb_cancel_func
Check activeServiceLoadBalancerCancel is nil or not before calling it
2023-05-25 16:19:18 +01:00
Timo Sluis
313c4c04f8 use config leasename instead of hardcoded
Signed-off-by: Timo Sluis <timo.sluis@live.nl>
2023-05-25 16:37:21 +02:00
lubronzhan
cd29e3d70a Check activeServiceLoadBalancerCancel is nil or not before calling it
Signed-off-by: lubronzhan <lzhan@vmware.com>
2023-05-22 14:36:15 -07:00
Daniel Finneran
6e8b3a9747 Merge pull request #569 from kube-vip/revert-502-iptables-nft
Revert "adding iptables-wrappers script to entrypoint"
2023-05-19 22:53:47 +01:00
Daniel Finneran
ef4995841a Revert "adding iptables-wrappers script to entrypoint" 2023-05-19 22:52:48 +01:00
Chris Privitere
0efed56a2a Merge pull request #502 from dockerpac/iptables-nft
adding iptables-wrappers script to entrypoint
2023-05-19 16:25:21 -05:00
Chris Privitere
fa248cca13 Merge pull request #567 from enkelprifti98/main
Add support for multiple BGP peers when using Equinix Metal annotations
2023-05-19 16:23:47 -05:00
Chris Privitere
24588d006a fix: formatting spaces on 217 2023-05-19 16:16:32 -05:00
Enkel Prifti
d7f4abafb8 Add support for multiple BGP peers when using Equinix Metal annotations
Using Equinix Metal annotations was limited to only the first BGP peer. This PR adds support for multiple BGP peer by looking at all bgp peer node annotations.

Signed-off-by: Enkel Prifti <enkelprifti@live.com>
2023-05-19 16:56:37 -04:00
Daniel Finneran
731545c666 Merge pull request #565 from enkelprifti98/main
Add BGP password support for Equinix Metal
2023-05-19 15:52:22 +01:00
Enkel Prifti
2a21b87b77 Add BGP password support for Equinix Metal
The Equinix Metal API integration was missing support for BGP session passwords so this PR adds the BGP password parameter.

Signed-off-by: Enkel Prifti <enkelprifti@live.com>
2023-05-18 20:09:26 -04:00
Daniel Finneran
b594d459fc Update Makefile 2023-05-15 12:29:34 +01:00
Daniel Finneran
8ea53f2b54 Merge pull request #562 from yaocw2020/ignoreServiceSecurity
Add annotation kube-vip.io/ignore-service-security
2023-05-15 09:49:05 +01:00
Canwu Yao
9ec6b3e8f5 Add annotation kube-vip.io/ignore-service-security
Skip service security configuration for the service whose annotation kube-vip.io/ignore-service-security is true

Signed-off-by: Canwu Yao <yaocanwu@gmail.com>
2023-05-15 11:24:50 +08:00
Daniel Finneran
2796185267 Merge pull request #557 from sykesm/kill-pkg-service 2023-05-11 19:29:35 +01:00
Matthew Sykes
cc362f7774 checks - fix things flagged by linting
Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>
2023-05-11 11:39:23 -04:00
Matthew Sykes
cfbf9b0458 Move helper from pkg/service and remove package
The pkg/service package is no longer used.

Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>
2023-05-11 11:38:45 -04:00
Daniel Finneran
ed59a13f10 Merge pull request #560 from yaocw2020/0502
Set iptables rules to restrict user access to ports other than the load balancer service port through the VIP
2023-05-11 08:49:43 +01:00
Canwu Yao
f2f73c00d0 Set iptables rules to limit traffic ports
Signed-off-by: Canwu Yao <yaocanwu@gmail.com>
2023-05-10 23:32:04 +08:00
Daniel Finneran
f03917e63f Merge pull request #561 from DrBu7cher/add_bgp_metrics_v1 2023-05-10 09:54:24 +01:00
Daniel Finneran
17eee86f2c Update main.yaml
Allow on-request builds.
2023-05-08 15:15:40 +01:00
Daniel Finneran
834aa94f75 Merge pull request #558 from thebsdbox/egress_namespace_isolation
This ensures rule cleaning only happens in a NS
2023-05-08 13:33:59 +01:00
Jonas Badstübner
4a2e72e811 refactor(metrics): better memory efficiency
Signed-off-by: Jonas Badstübner <jonas.badstuebner@hetzner-cloud.de>
2023-05-08 10:17:51 +02:00
Jonas Badstübner
68e6a940a2 feat(metrics): implement bgp_session_info
Signed-off-by: Jonas Badstübner <jonas.badstuebner@hetzner-cloud.de>
2023-05-08 10:17:51 +02:00
Jonas Badstübner
386d1514c2 feat(metrics): add bgp_session_info
Signed-off-by: Jonas Badstübner <jonas.badstuebner@hetzner-cloud.de>
2023-05-08 10:17:51 +02:00
Jonas Badstübner
640743a2de feat(bgp-server): add peer state change callback
Signed-off-by: Jonas Badstübner <jonas.badstuebner@hetzner-cloud.de>
2023-05-08 10:17:51 +02:00
Canwu Yao
1474fcf369 Support changing load balancer IP
Signed-off-by: Canwu Yao <yaocanwu@gmail.com>
2023-05-07 12:00:44 +08:00
Dan Finneran
e6e4d1cf08 This ensures rule cleaning only happens in a NS
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-05-05 16:51:03 +00:00
Daniel Finneran
60957d64aa Merge pull request #555 from sykesm/ipvs-ipv6
Ignore different family on IPVS delete
2023-05-03 16:08:08 +02:00
Matthew Sykes
37364882fd Ignore different family on IPVS delete
Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>
2023-05-03 08:31:29 -04:00
Daniel Finneran
e0a9e70664 Merge pull request #553 from tuxtof/fix-lb-annotation
fix LB annotations
2023-05-03 10:48:52 +02:00
Daniel Finneran
839011c29d Merge pull request #554 from sykesm/ipvs-ipv6
Use correct address family for ipvs destinations
2023-05-03 10:48:29 +02:00
Matthew Sykes
7fcf0f1b65 Use correct address family for ipvs destinations
When IPv6 addresses are present in node.Status.Addresses, the
IPVSLoadBalancer parses the addresses and attempts to add them as an
IPv4 destinations. This results in useless entries in the service table
that only hold the last 32 bits of address.

This change does two things:
- uses the appropriate address family when creating the service
- ignores backend addresses that use a different address family than the
  service

This avoids the immediate problem of using the wrong address family for
IPv6 destinations and the useless entries in the service table.

Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>
2023-04-30 17:38:14 -04:00
Christophe Jauffret
b33da242e8 fix LB annotations
Signed-off-by: Christophe Jauffret <reg-github@geo6.net>
2023-04-29 08:11:05 +02:00
Daniel Finneran
27444b31ee Merge pull request #546 from W1zzardTPU/main
Add support for lbClassName
2023-04-26 16:08:03 +02:00
W1zzardTPU
f1eef8f07d Add support for lbClassName 2023-04-23 20:36:59 +02:00
Daniel Finneran
e4f42a3a44 Merge pull request #540 from thebsdbox/iptables
Adds nftables as an option, and fixes a panic
2023-04-14 09:35:07 +01:00
Dan Finneran
6c5b39b02a Merge branch 'iptables' of github.com:thebsdbox/kube-vip into iptables 2023-04-14 08:30:01 +00:00
Dan Finneran
e8319a6464 dont lint old files
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-04-14 08:29:51 +00:00
Daniel Finneran
7e4f596b5d Merge branch 'main' into iptables 2023-04-14 09:14:42 +01:00
Dan Finneran
eac9d2b8be Adds nftables as an option, and fixes a panic
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-04-14 08:13:27 +00:00
Chris Privitere
2b7c02c614 Merge pull request #538 from lubronzhan/topic/lubron/kube-vip_update_version_variable
Update makefile to accept variable to update version
2023-04-05 08:57:01 -05:00
lubronzhan
aa7eabd4fb Update makefile to accept variable to update version
Signed-off-by: lubronzhan <lzhan@vmware.com>
2023-04-04 22:48:59 -07:00
Daniel Finneran
aeabe547ff Merge pull request #536 from thebsdbox/iptables
Adds ability to specifc iptables or nftables
2023-04-04 15:11:25 +01:00
Daniel Finneran
8febca00ee Update ci.yaml 2023-04-04 15:02:33 +01:00
Daniel Finneran
6037cc7a6e Merge pull request #531 from lubronzhan/topic/lubron/fix_doc_link
Fix the doc link
2023-04-04 14:53:35 +01:00
Dan Finneran
9119597b94 final fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-04-04 13:52:45 +00:00
Dan Finneran
9e88b0003f Further linting fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-04-04 13:44:03 +00:00
Dan Finneran
f4d193f7fb Merge branch 'iptables' of github.com:thebsdbox/kube-vip into iptables 2023-04-04 08:46:58 +00:00
Dan Finneran
e604e4fe26 lint fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-04-04 08:45:56 +00:00
Daniel Finneran
8590fefa05 Merge branch 'main' into iptables 2023-04-03 18:19:30 +01:00
Dan Finneran
ae25e6bcf3 Adds ability to specifc iptables or nftables
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-04-03 17:18:00 +00:00
Daniel Finneran
8af0391bc9 Merge pull request #528 from lubronzhan/topic/lubron/deprecate_loadbalancerip
Deprecate loadbalancerIP, use annotation to fetch service loadbalancerIP
2023-03-16 16:23:32 +00:00
Pierre-Antoine Couaillier
e1bafbe699 Merge branch 'kube-vip:main' into iptables-nft 2023-03-09 14:22:36 +01:00
lubronzhan
cc63a13303 Fix the doc link
Signed-off-by: lubronzhan <lubronzhan@gmail.com>
2023-03-09 00:15:26 -08:00
Daniel Finneran
fb66fe0708 Merge pull request #529 from lubronzhan/topic/lubron/update_readme 2023-03-07 07:00:00 +00:00
lubronzhan
332546dd13 Update readme
Signed-off-by: lubronzhan <lzhan@vmware.com>
2023-03-06 16:01:31 -08:00
lubronzhan
a9932ec148 Deprecate loadbalancerIP
Add new annotation kube-vip.io/loadbalancerIPs to specify the loadbalancer ip for service
Now ip address fetched from loadbalancer service are first fetched from annotation, then fallback to service spec
Unit test

Signed-off-by: lubronzhan <lzhan@vmware.com>
2023-03-06 15:53:38 -08:00
Daniel Finneran
a422d246bb Merge pull request #526 from mrueg/bump-deps 2023-03-06 18:21:44 +00:00
Manuel Rüger
798b9c4b8f go.mod: Bump dependencies
Also replace github.com/ghodss/yaml with sigs.k8s.io/yaml (maintained
fork).

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2023-03-05 12:40:54 +01:00
Daniel Finneran
c7536f180e Merge pull request #524 from tylerschultz/recreate-vip-on-dadfailed
Readd VIP if address has dadfailed flag
2023-03-02 17:48:52 +01:00
Tyler Schultz
61d5deb0b9 Readd VIP if address has dadfailed flag
Remove the address from in the interface case that a duplicate address is detected.
Without this change, kube-vip will take no corrective action, and the
address will remain in dadfailed state. Removing and re adding the
address causes duplicate address detection to happen again, hopefully
successfully the next time.

We suspect dadfailed happens when a new leader is elected and the old
leader is too slow or fails to delete the IP address.

Co-authored-by: Aidan Obley <aobley@vmware.com>
Co-authored-by: Christian Ang <angc@vmware.com>
Signed-off-by: Tyler Schultz <tschultz@vmware.com>
2023-03-01 22:41:10 +00:00
Daniel Finneran
49c871bd93 Merge pull request #521 from ocobleseqx/support_new_equinix_ccm_annotations
check for new equinix ccm annotations
2023-02-27 11:58:56 +01:00
Daniel Finneran
9c6b87c43c Update README.md 2023-02-27 09:44:42 +00:00
ocobleseqx
0320d256f3 replace packet with equinix metal in comments and logs
Signed-off-by: ocobleseqx <oscar.cobles@eu.equinix.com>
2023-02-24 13:33:16 +01:00
ocobleseqx
a691b3f128 check for new equinix ccm annotations
Signed-off-by: ocobleseqx <oscar.cobles@eu.equinix.com>
2023-02-23 19:41:20 +01:00
Daniel Finneran
a92c536de2 Update main.yaml 2023-02-21 08:56:40 +00:00
Daniel Finneran
323f054ca5 Merge pull request #519 from kube-vip/final-0.5.x-release
Update Makefile
2023-02-20 18:44:38 +01:00
Daniel Finneran
53d33d79f4 Update Makefile 2023-02-20 17:36:39 +00:00
Daniel Finneran
a31d9a65f2 Merge pull request #515 from kube-vip/dependabot/go_modules/golang.org/x/net-0.7.0
Bump golang.org/x/net from 0.2.0 to 0.7.0
2023-02-20 17:00:31 +01:00
Daniel Finneran
bcaa8bede6 Merge pull request #518 from thebsdbox/actions_fixes
Actions fixes
2023-02-20 16:53:38 +01:00
Dan Finneran
18d11ea252 Set correct labels.
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-20 15:53:10 +00:00
Dan Finneran
3971c7de0b Tidies actions.
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-20 15:51:33 +00:00
Daniel Finneran
0c14497985 Update anchore-syft.yml 2023-02-20 09:33:36 +00:00
Daniel Finneran
3caa8fdec2 Merge pull request #517 from thebsdbox/2e2eLint
lint fixes
2023-02-20 10:04:14 +01:00
Daniel Finneran
23fda78b45 Update ci.yaml
removes random manifest generate
2023-02-20 08:41:38 +00:00
Dan Finneran
aed43b2def final fix to makefile
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-19 16:39:08 +00:00
Dan Finneran
790d0b5291 lint fix
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-19 16:27:27 +00:00
Dan Finneran
7802027f67 lint fixes
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-19 16:09:25 +00:00
Daniel Finneran
606f3e30d5 Update ci.yaml 2023-02-19 16:02:42 +00:00
Daniel Finneran
90f6234d71 Merge pull request #516 from thebsdbox/e2eServices
Adds e2e testing of services
2023-02-19 16:59:13 +01:00
Dan Finneran
98c885dff5 Adds e2e testing of services
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-19 15:58:03 +00:00
dependabot[bot]
acea12d09a Bump golang.org/x/net from 0.2.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.2.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.2.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-17 14:14:28 +00:00
Daniel Finneran
9d15cbe8ca Merge pull request #494 from fimmicon/patch-1
Fix broken link in docs
2023-02-17 15:11:51 +01:00
Daniel Finneran
a3644baa7d Merge pull request #513 from thebsdbox/endpoint_fixes
Fixes and testing for endpoints
2023-02-15 15:09:22 +01:00
Dan Finneran
c10b4105b9 Fixes and testing for endpoints
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-15 13:52:25 +00:00
Daniel Finneran
62d826fbe5 Merge pull request #512 from thebsdbox/endpoint_leadership
Ensures a leadership will be restarted
2023-02-10 19:30:25 +00:00
Dan Finneran
285f4e514c this should be it
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-10 18:14:17 +00:00
Dan Finneran
71b490d735 stupid linter
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-10 18:09:55 +00:00
Dan Finneran
b62b331be8 more linting
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-10 18:02:46 +00:00
Dan Finneran
9ab8b909bf linter fix
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-10 16:41:48 +00:00
Dan Finneran
d93e0cdf9c Ensures a leadership will be restarted
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-10 16:36:20 +00:00
Daniel Finneran
4f0c163b89 Merge pull request #510 from spideyfusion/fix-service-delete
Fix service deletion not registering
2023-02-10 16:35:41 +00:00
Daniel Finneran
a66b84a77e Update Makefile 2023-02-08 14:05:37 +00:00
Daniel Finneran
b446a80d9b Merge pull request #511 from thebsdbox/context_fix
Adds services testing and fixes missing context
2023-02-08 14:05:13 +00:00
Dan Finneran
aa296d8211 Fixes to linting
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-08 13:57:01 +00:00
Dan Finneran
3a8a94fcc9 Adds services testing and fixes missing context
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-08 12:58:44 +00:00
Daniel Finneran
3ff1eb2f99 Merge pull request #509 from thebsdbox/main
Fixes to negative waitgroup
2023-02-07 08:59:43 +00:00
Petar Obradović
9f728278fd Fix service deletion not registering
Signed-off-by: Petar Obradović <petar.obradovic@sofascore.com>
2023-02-02 11:58:41 +01:00
Dan Finneran
7ad4e27084 Fixes to negative waitgroup
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-02-02 10:30:35 +00:00
Daniel Finneran
1b4bba0800 New Release 2023-01-19 15:10:21 +00:00
Daniel Finneran
1d1a8bbd55 Merge pull request #503 from thebsdbox/api_failure
Keep watching services after losing leadership
2023-01-19 15:09:59 +00:00
Dan Finneran
631960fb0c Keep watching services after losing leadership
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2023-01-16 20:57:34 +00:00
Pierre-Antoine Couaillier
af5860633b adding iptables-wrappers script to entrypoint
Signed-off-by: Pierre-Antoine Couaillier <pa.couaillier@gmail.com>
2023-01-16 16:47:56 +00:00
Daniel Finneran
c9ce2cf779 Merge pull request #498 from kriansa/patch-1
Fix watching for endpoints RBAC rule
2023-01-09 16:38:34 +00:00
Daniel Finneran
f28a448d0b Merge pull request #500 from imzyxwvu/fix/ipv6-path
Enable IPv6 peering and VIP advertisement and improve BGP support.
2023-01-09 16:36:52 +00:00
zyxwvu Shi
d01903194b doc: Update bgp_peers description
Signed-off-by: zyxwvu Shi <i@shiyc.cn>
2023-01-08 16:51:17 +08:00
zyxwvu Shi
1dfda79af8 bgp: Make password and multiHop params optional
Also fix a CodeQL alert.

Signed-off-by: zyxwvu Shi <i@shiyc.cn>
2023-01-08 16:51:17 +08:00
zyxwvu Shi
b83a993805 bgp: Allow IPv6 BGP peer to be specified with brackets
Ability to specify BGP port is removed, for two reasons:
1. IPv6 peer addresses contain colons, and the SpiltN func breaks IPv6 addresses.
2. Typical network devices do not allow changing BGP port, so this is rarely used.

Signed-off-by: zyxwvu Shi <i@shiyc.cn>
2023-01-08 16:51:17 +08:00
zyxwvu Shi
95ae62e9eb bgp: Remove unused Config fields
Signed-off-by: zyxwvu Shi <i@shiyc.cn>
2023-01-08 16:51:17 +08:00
zyxwvu Shi
35a93d8275 bgp: Advertise IPv6 host prefix using MpReachNLRIAttribute
MP-BGP protocol requires IPv6 prefixes to be advertised in a path attribute called MP_REACH_NLRI. Without the attribute non-IPv4 prefixes can not be advertised. This prevents IPv6 loadBalancerIps and control plane addresses from being advertised to the network.

Signed-off-by: zyxwvu Shi <i@shiyc.cn>
2023-01-08 16:51:17 +08:00
zyxwvu Shi
1dc74c4249 bgp: Let gobgp figure out NEXT_HOP path attribute
According to UpdatePathAttrs in gobgp internal/pkg/table/path.go, gobgp will fill NEXT_HOP with BGP session local address if given NEXT_HOP is an unspecified address, such as 0.0.0.0 and ::. It is better to use that address as NEXT_HOP, since the BGP TCP connection ensures the address reaches the node.

See: https://github.com/osrg/gobgp/blob/v3.10.0/internal/pkg/table/path.go#L223

Signed-off-by: zyxwvu Shi <i@shiyc.cn>
2023-01-06 22:51:41 +08:00
Daniel Finneran
c69edfe1e6 Merge pull request #493 from GeorgeGedox/patch-1
Update broken links in k3s docs
2022-12-30 16:03:33 +00:00
Daniel Pereira
9c7a1e60be fix: endpoints watcher
Without this specific ClusterRole rule, kube-vip would not be able to listen for `endpoints` changes when deployed as a DaemonSet, thus causing the IP addresses not being announced and the following error message every second:

```
E1227 20:37:20.290479       1 retrywatcher.go:130] "Watch failed" err="unknown (get endpoints)"
```
2022-12-27 17:46:44 -03:00
Efim
9c60351867 Fix broken link in docs 2022-12-06 14:27:18 +02:00
George V
45aae3ee7c Update broken links in k3s docs
Fix broken documentation links
2022-12-04 00:01:44 +02:00
Daniel Finneran
f830b389da Update Makefile 2022-12-01 11:23:21 +00:00
Daniel Finneran
3026769caf Merge pull request #490 from thebsdbox/goroutine_gc
garbage collection for goroutines
2022-12-01 11:19:20 +00:00
Dan Finneran
1e4ef9f2b1 garbage collection for goroutines
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-12-01 11:09:54 +00:00
Daniel Finneran
26f1b9ae67 Merge pull request #489 from lubronzhan/cve_2022_nov_28
Fix CVE
2022-11-29 20:16:24 +00:00
lubronzhan
f4a9e1b65b Fix several CVEs
Signed-off-by: lubronzhan <lzhan@vmware.com>
2022-11-28 18:11:51 -08:00
Daniel Finneran
96134ccbe5 Merge pull request #487 from stevesloka/linter-errors
linter: Clean up some linter errors
2022-11-28 13:44:12 +00:00
Steve Sloka
6d5533ca58 linter: Clean up some linter errors
Cleans up errors found when running `make` that golangci-lint
found.

Signed-off-by: Steve Sloka <steve@stevesloka.com>
2022-11-26 11:57:17 -05:00
Daniel Finneran
99b261a685 Merge pull request #485 from thebsdbox/reconcilliation_testing
added testing
2022-11-17 16:18:15 +00:00
Dan Finneran
f84c4aaa8b added testing
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-17 16:17:18 +00:00
Daniel Finneran
0aa339ec00 Merge pull request #484 from thebsdbox/flush_conntrack
Adds an annotation for flushing conntrack rules
2022-11-16 14:54:42 +00:00
Dan Finneran
139add9d51 Adds an annotation for flushing conntrack rules
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-16 13:20:17 +00:00
Daniel Finneran
06c5f784b8 Merge pull request #483 from thebsdbox/address_annotation
Tidies the annotations
2022-11-16 13:04:12 +00:00
Dan Finneran
dc40c4dc0b Tidies the annotations
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-16 13:03:27 +00:00
Daniel Finneran
76c5711129 Merge pull request #482 from thebsdbox/egress_clean_fix
Fix to egress rules
2022-11-10 11:28:42 +00:00
Daniel Finneran
7ebb54961b Update release.yaml
Allows manual trigger
2022-11-10 10:58:33 +00:00
Dan Finneran
47a8832d89 Fix to egress rules
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-10 10:52:53 +00:00
Daniel Finneran
1dc035f606 Update Makefile
Bumping for a new release!
2022-11-09 17:10:02 +00:00
Daniel Finneran
63e513ee34 Merge pull request #480 from thebsdbox/further_fixes
logging and fixed an issue with multiple elections
2022-11-09 17:09:32 +00:00
Dan Finneran
e599a33330 logging and fixed an issue with multiple elections
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-09 16:49:33 +00:00
Daniel Finneran
46d662ac14 Merge pull request #478 from thebsdbox/dangling_rules
Fixes to where iptables are gc
2022-11-07 13:41:26 -05:00
Dan Finneran
ccaf8119da Fixes to where iptables are gc
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-07 18:40:48 +00:00
Daniel Finneran
d8654781a9 Merge pull request #477 from thebsdbox/subnet
Adds capability to specify a subnet for the VIP
2022-11-07 12:46:09 -05:00
Dan Finneran
5e38c81290 Adds capability to specify a subnet for the VIP
Signed-off-by: Dan Finneran <daniel.finneran@gmail.com>
2022-11-07 17:43:55 +00:00
Daniel Finneran
f052777b6b Merge pull request #476 from thebsdbox/rule_cleaning
Adds tags to rules so that we can garbage collect.
2022-11-07 10:41:46 -05:00
Dan Finneran
af1a1e51c8 Adds tags to rules so that we can garbage collect. 2022-11-07 15:25:34 +00:00
Daniel Finneran
315fa695f4 Merge pull request #474 from thebsdbox/cached_services
This fixes an issue with the cache being wiped
2022-11-02 13:28:29 -04:00
thebsdbox
ccaef3d750 This fixes an issue with the cache being wiped
Signed-off-by: thebsdbox <dan@thebsdbox.co.uk>
2022-11-02 16:18:17 +00:00
Daniel Finneran
3d7c1229e5 Merge pull request #473 from thebsdbox/cidr
Adds the capability to exclude egress traffic
2022-10-31 12:16:47 -04:00
thebsdbox
f173c5f979 Adds the capability to exclude egress traffic
Signed-off-by: thebsdbox <dan@thebsdbox.co.uk>
2022-10-31 16:07:35 +00:00
Daniel Finneran
28eb301d32 Merge pull request #472 from thebsdbox/leaderElection
Fixes all leaderElection code to use config
2022-10-31 11:53:03 -04:00
thebsdbox
a4b11e6854 Fixes all leaderElection code to use config
Signed-off-by: thebsdbox <dan@thebsdbox.co.uk>
2022-10-31 15:52:29 +00:00
Daniel Finneran
4073cc3a8b Merge pull request #470 from thebsdbox/logging
Fixes to logging
2022-10-31 10:29:54 -04:00
thebsdbox
8687d28eb4 Fixes to logging
Signed-off-by: thebsdbox <dan@thebsdbox.co.uk>
2022-10-31 13:22:17 +00:00
Daniel Finneran
5330992f9b Merge pull request #469 from thebsdbox/testing_adds
Adds some additional checking scripts
2022-10-31 08:55:59 -04:00
thebsdbox
6c52800bd4 Adds some additional checking scripts 2022-10-31 12:54:53 +00:00
Daniel Finneran
76d5ad8a49 Merge pull request #467 from abhay-krishna/fix-typo
Fix typo in EnableControlPlane config option
2022-10-19 09:26:00 +01:00
Abhay Krishna Arunachalam
7321a06dae Fix typo in EnableControlPlane config option
Signed-off-by: Abhay Krishna Arunachalam <arnchlm@amazon.com>
2022-10-18 22:22:58 -07:00
Daniel Finneran
34b05aa525 Merge pull request #460 from mrueg/update-deps
Update deps / build with go 1.19
2022-10-12 09:22:32 +01:00
Manuel Rüger
6004892920 go.mod: Update dependencies
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2022-10-11 20:08:13 +02:00
Manuel Rüger
ea7ab1e4d6 Update to go 1.19
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2022-10-11 20:08:11 +02:00
Daniel Finneran
c9a4d584b4 Delete release_iptables.yaml 2022-10-11 13:13:45 +01:00
Daniel Finneran
bc260ce03a Update release.yaml 2022-10-11 13:13:31 +01:00
Daniel Finneran
28b58dc013 Create release_iptables.yaml 2022-10-11 09:45:07 +01:00
Daniel Finneran
256f866d43 Update release.yaml 2022-10-11 09:44:23 +01:00
Daniel Finneran
56362fb47e Update release.yaml 2022-10-10 20:27:10 +01:00
Daniel Finneran
5c859f42f5 Update Makefile 2022-10-10 16:25:16 +01:00
Daniel Finneran
834b5aae54 Merge pull request #459 from thebsdbox/egress_ports
Adds ports and namespaces
2022-10-10 16:24:10 +01:00
thebsdbox
daa7d852ab linting fixes 2022-10-10 14:12:36 +01:00
thebsdbox
651038ada2 Adds ports and namespaces 2022-10-10 13:48:54 +01:00
Daniel Finneran
97eae7c528 Merge pull request #456 from thebsdbox/egress_stability
Adds stability and warnings to egress
2022-09-28 12:06:16 +01:00
Daniel Finneran
c41df19a36 Update mainiptables.yaml 2022-09-28 12:01:22 +01:00
Daniel Finneran
88af581958 Update mainiptables.yaml 2022-09-28 11:56:39 +01:00
Daniel Finneran
00cd131e2e Update mainiptables.yaml 2022-09-28 11:55:16 +01:00
Daniel Finneran
e6ae07f404 Create mainiptables.yaml 2022-09-28 11:54:38 +01:00
Daniel Finneran
2a1152f4d0 Merge pull request #449 from daper/main
Add random MAC address generation for DHCP
2022-09-28 11:44:55 +01:00
thebsdbox
36f42300c4 Adds stability and warnings to egress 2022-09-28 11:44:02 +01:00
Daniel Finneran
65c175d185 Merge pull request #445 from thebsdbox/egress
This adds the initial code for egress (SNAT).
2022-09-15 15:45:28 +03:00
thebsdbox
6620440c95 Final first push at Egress 2022-09-15 13:41:42 +01:00
daper
023ddbafd1 Add random MAC address generation for DHCP
Signed-off-by: David Peralta <david@daper.email>
2022-09-13 16:37:01 +02:00
thebsdbox
98f5c73919 Fixes to iptables and endpoint watcher 2022-09-13 09:09:20 +01:00
Daniel Finneran
de206eb46a Merge pull request #440 from cprivitere/Build-fixes
Build-fixes
2022-09-11 08:52:06 +01:00
Daniel Finneran
0b82de9dcf Merge pull request #446 from alexandrevilain/fix/wrong-env-var 2022-09-07 20:29:33 +01:00
Alexandre Vilain
db1ed82510 fix --table flag should add vip_routingtable env var not vip_wireguard
Signed-off-by: Alexandre Vilain <alexandre.vilain@me.com>
2022-09-07 21:03:17 +02:00
thebsdbox
ba20ae1725 This adds the initial code for egress (SNAT). 2022-09-06 15:18:48 +01:00
Daniel Finneran
bb4c815c5c Update anchore-syft.yml 2022-08-30 14:28:10 +01:00
Daniel Finneran
8a0eb9a661 Update anchore-syft.yml 2022-08-30 14:26:29 +01:00
Chris Privitere
8eaafee0f5 Add ReadHeaderTimeout
Resolves golanglint-ci complaint

Signed-off-by: Chris Privitere <23177737+cprivitere@users.noreply.github.com>
2022-08-29 15:30:10 -05:00
Chris Privitere
7e97ef0eef go fmt
Signed-off-by: Chris Privitere <23177737+cprivitere@users.noreply.github.com>
2022-08-29 15:29:42 -05:00
Daniel Finneran
85cb26d305 Update anchore-syft.yml 2022-08-26 12:52:07 +01:00
Daniel Finneran
6b12d18ab2 Update anchore-syft.yml 2022-08-26 09:39:04 +01:00
Daniel Finneran
a29cf4ea80 Update anchore-syft.yml
Fixes buildkit dependency
2022-08-26 09:36:29 +01:00
Daniel Finneran
494283d511 Add Anchore SBOM creation 2022-08-26 09:31:34 +01:00
Daniel Finneran
bb0d1a3db0 Merge pull request #435 from abhinavmpandey08/exclusive-lb-class 2022-08-15 19:05:38 +01:00
Abhinav Pandey
c50465c09c Enable kube-vip to only respond to svc with kube-vip's lb class
Signed-off-by: Abhinav Pandey <abhinavmpandey08@gmail.com>
2022-08-15 11:00:25 -07:00
Daniel Finneran
ff040f2def Merge pull request #434 from valtzu/main
Allow fixed virtual MAC for DHCP VIPs
2022-08-10 11:25:30 +01:00
valtzu
14100f0aec Allow fixed virtual MAC for VIPs via DHCP
Closes #354

Signed-off-by: valtzu <valtzu@gmail.com>
2022-08-08 00:13:27 +03:00
Daniel Finneran
708f4b3ebf Update FUNDING.yml 2022-08-07 12:24:32 +01:00
Daniel Finneran
1ef3592305 Update Makefile 2022-07-22 09:27:24 +01:00
Daniel Finneran
a00040dd40 Merge pull request #427 from thebsdbox/add-route-on-lead
Adds a route if leader
2022-07-21 14:32:02 +01:00
thebsdbox
31786074a8 Adds a route if leader 2022-07-21 14:30:54 +01:00
Daniel Finneran
a70b965b52 Update FUNDING.yml 2022-07-15 22:34:04 +01:00
Daniel Finneran
579d9dd89f Merge pull request #423 from kube-vip/thebsdbox-sponsor
Create FUNDING.yml
2022-07-15 09:03:02 +01:00
Daniel Finneran
ef78dcc5e5 Create FUNDING.yml 2022-07-15 08:53:50 +01:00
Daniel Finneran
49f4516209 Merge pull request #422 from scuzhanglei/fix-close-nil-chanel-panic
Fixes close nil channel panic
2022-07-14 13:10:59 +01:00
zhanglei
e6048c3eab Fixes close nil channel panic
Signed-off-by: zhanglei <zhanglei@smartx.com>
2022-07-14 19:40:16 +08:00
Daniel Finneran
d533e40796 Merge pull request #417 from thebsdbox/prometheus
prometheus changes
2022-07-05 14:15:38 +01:00
thebsdbox
93dfe4d372 prometheus changes 2022-07-01 17:01:59 +01:00
Daniel Finneran
c7c4f8d31a Merge pull request #416 from thebsdbox/table_mode
Table mode is now added to kube-vip
2022-06-30 14:17:34 +01:00
thebsdbox
9d15e0ac8b fixes to missing env 2022-06-30 11:25:40 +01:00
thebsdbox
1bcd101b53 Table mode is now added to kube-vip 2022-06-29 16:08:02 +01:00
Daniel Finneran
c6f37f433a Merge pull request #414 from thebsdbox/loadBalancerClass
Adds loadBalancerClass
2022-06-27 19:07:02 +01:00
thebsdbox
46b4325187 linting fix 2022-06-27 18:59:25 +01:00
thebsdbox
169eb0c7aa Adds loadBalancerClass 2022-06-27 18:08:09 +01:00
Daniel Finneran
b8d3ec8087 Merge pull request #412 from thebsdbox/wireguard
Wireguard support (basic)
2022-06-27 18:06:14 +01:00
thebsdbox
fcb24e7eab Fixes to the design 2022-06-27 17:41:33 +01:00
thebsdbox
8d0db81225 linter fixes 2022-06-25 16:57:10 +01:00
thebsdbox
ccee5ab7bd Wireguard support (basic) 2022-06-25 16:42:26 +01:00
Daniel Finneran
3c2eac15d4 Merge pull request #410 from thebsdbox/traffic_policy
This enables local traffic policy
2022-06-21 19:21:36 +01:00
thebsdbox
5485bbdcab This enables local traffic policy 2022-06-21 15:53:41 +01:00
Daniel Finneran
d815d3cb79 Merge pull request #407 from thebsdbox/leader_per_service
Initial design of leaderElection per service
2022-06-21 15:52:58 +01:00
thebsdbox
f51aa1f60f formatting fixes 2022-06-21 15:19:59 +01:00
thebsdbox
efea371edc Security fixes 2022-06-21 15:14:47 +01:00
thebsdbox
7d9062fd0e linting 2022-06-21 13:59:27 +01:00
thebsdbox
8d4f0e5206 annotations and working leaderElection 2022-06-21 13:57:13 +01:00
thebsdbox
b2df1cba3d Fixes to function signature 2022-06-08 13:14:38 +01:00
thebsdbox
840a2ba2b1 Initial design of leaderElection per service 2022-06-08 12:57:56 +01:00
Daniel Finneran
f22f6d4e93 Merge pull request #405 from thebsdbox/e2e
e2e test
2022-06-01 17:15:38 +02:00
thebsdbox
7c22c78a75 e2e test 2022-06-01 16:14:55 +01:00
Daniel Finneran
0487080505 Merge pull request #404 from thebsdbox/ignore_wrong_services
Ignore services that aren't LoadBalancers
2022-06-01 13:04:24 +02:00
thebsdbox
cef1852099 Ignore services that aren't LoadBalancers 2022-06-01 11:52:19 +01:00
Daniel Finneran
ac53446f33 Merge pull request #396 from AxiomSamarth/get-lease
set kubernetes:6443 as default hostname
2022-05-30 17:54:19 +02:00
Daniel Finneran
ca61bfdbe3 Merge pull request #401 from thebsdbox/em_annotations
Packet to equinixmetal
2022-05-30 17:54:05 +02:00
thebsdbox
f8d3152e93 disable new annotations 2022-05-30 13:30:20 +01:00
thebsdbox
f1841f70ef Packet to equinixmetal 2022-05-30 11:15:07 +01:00
AxiomSamarth
da7ba0b9a6 set kubernetes:6443 as default hostname
Signed-off-by: AxiomSamarth <sdeyagond@microsoft.com>
2022-05-14 13:00:19 +05:30
Daniel Finneran
b9014ae32a Update README.md 2022-05-13 15:32:47 +01:00
Daniel Finneran
51a1a0bb61 Merge pull request #395 from AxiomSamarth/get-lease
Set api-endpoint to host for incluster deployment
2022-05-13 14:20:38 +01:00
AxiomSamarth
75a2323448 set api-endpoint to host for incluster deployment
Signed-off-by: AxiomSamarth <sdeyagond@microsoft.com>
2022-05-13 18:28:09 +05:30
Daniel Finneran
7a7425efdf Update Makefile 2022-04-21 09:24:11 +01:00
Daniel Finneran
d4683401b6 Merge pull request #351 from yaocw2020/release-bug
Fix DHCP release bug
2022-04-21 09:12:07 +01:00
yaocw2020
e6edf3a3de Fix DHCP release bug
The macvlan interface could not be deleted until the DHCP client has
released the IP.

If the network manager in the operating system uses DHCP to obtain an IP
for the network card, it will occupy the DHCP client port. In this case
the release function will fail because the unicast connection with UDP
socket need the same port. Update dhcp package and use a raw socket.

Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2022-04-21 12:38:01 +08:00
Daniel Finneran
40cff6bc50 Merge pull request #389 from claudio4/main
Treat interfaces with unknown state as valid
2022-04-18 10:00:16 +01:00
Claudio Yanes
428d306030 Fix missing interface name in warning message
Signed-off-by: Claudio Yanes <me@claudio4.com>
2022-04-14 13:34:09 +01:00
Claudio Yanes
5fbb11fa06 Treat interfaces with unknown state as valid
Previous commits addressed the issue of interface being incorrectly marked as
down for loopback (1a4465e) and point-to-point (051bb1f) interfaces by directly
passing the test when the interface is identified a any of those types. Both
commits failed to address the core issue, those interfaces (and many others) do
not publish their operational state resulting in the state UNKOWN. With this
commit, now interfaces with unknown status are accepted but the user is warned as
he needs to manually ensure that the interface is ready to handle traffic.
Fix #385

Signed-off-by: Claudio Yanes <me@claudio4.com>
2022-04-14 13:34:09 +01:00
Daniel Finneran
8185df46b9 Merge pull request #388 from mrueg/ignore-p2p 2022-04-09 14:08:20 +01:00
Manuel Rüger
051bb1f414 Don't check status on Point-To-Point interfaces
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2022-04-09 00:20:16 +02:00
Daniel Finneran
b883939f6e Merge pull request #387 from mrueg/gobgpv
Update to gobgp/v3, ndp/v0.10.0 / go 1.18
2022-04-05 14:07:06 +01:00
Manuel Rüger
88c9075116 Update golangci-lint
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2022-04-05 00:31:42 +02:00
Manuel Rüger
fae208e459 Update to gobgp/v3, ndp/v0.10.0 / go 1.18
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2022-04-05 00:31:42 +02:00
Daniel Finneran
1279570f11 Merge pull request #386 from thebsdbox/testing_n_logs
Update to automated testing and clear msg
2022-04-04 20:54:45 +01:00
thebsdbox
d7b49a0f0f Update to automated testing and clear msg 2022-04-04 14:49:38 +01:00
Daniel Finneran
7b0bd4061f Update Makefile 2022-04-01 15:59:54 +01:00
Daniel Finneran
342161068a Merge pull request #384 from yaocw2020/supportChangingVIP
support changing the VIP of services
2022-04-01 15:57:58 +01:00
yaocw2020
c81c8c1865 support changing the VIP of services
- Support changing the VIP of services
- Refactory the manager.syncServices to improve code readability

Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2022-03-29 00:23:13 +08:00
Daniel Finneran
344cb491eb Merge pull request #383 from yaocw2020/gratuitous-arp 2022-03-24 15:35:52 +00:00
yaocw2020
9bd837f0c6 The gratuitous arp should be sent periodically
Related issue: https://github.com/kube-vip/kube-vip/issues/382

Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2022-03-24 12:24:55 +08:00
Daniel Finneran
b609330c48 Merge pull request #370 from rohitsakala/main
Add s390x arch support
2022-02-28 17:19:54 +00:00
Venkata Krishna Rohit Sakala
8afd9487ff Add s390x arch support
Signed-off-by: Venkata Krishna Rohit Sakala <rohitsakala@gmail.com>
2022-02-28 14:35:20 +01:00
Daniel Finneran
48add4ddeb Merge pull request #366 from mrueg/go-1.17
Build with go-1.17, bump dependencies
2022-02-28 10:02:31 +00:00
Daniel Finneran
ac83920e2c Merge pull request #365 from thebsdbox/retry_update
Adds retry to status update
2022-02-28 10:02:09 +00:00
Manuel Rüger
3f91c045d4 Build with go-1.17, bump dependencies
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2022-02-18 13:23:08 +01:00
Daniel Finneran
027703ec0f Merge pull request #364 from rawkode/fix/correctly-spell-prometheus
fix: spell prometheus correctly
2022-02-17 14:43:39 +00:00
thebsdbox
58da24127e Adds retry to status update 2022-02-17 14:42:56 +00:00
David Flanagan
1fb1de9990 fix: spell prometheus correctly 2022-02-14 18:50:46 +00:00
Daniel Finneran
7038960a24 Merge pull request #362 from thebsdbox/new_release
New release
2022-02-09 07:52:01 -05:00
thebsdbox
ff3a010a8d Security fix for unit 2022-02-09 11:37:47 +00:00
thebsdbox
e9ea905693 Fix environment variable and tidy 2022-02-09 11:16:42 +00:00
thebsdbox
8448c1224e Bump new release to 4.2 2022-02-09 11:10:37 +00:00
Chris Privitere
c5049407c7 Merge pull request #350 from kube-vip:cprivite/issue349
Merge pull request #348 from cprivite/cprivite/issue342
2022-01-11 16:14:34 -06:00
Chris Privitere
1e0523fa8a Use same formatting for main and release.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-11 15:28:56 -06:00
Chris Privitere
d1aa8bcb6f Switch to doing the tags with a github context.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-11 15:09:22 -06:00
Chris Privitere
ae22483f08 Add id as per docker-build-push pattern.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-11 15:08:50 -06:00
Chris Privitere
ad355fb6f6 Add login for github packages.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-11 15:08:30 -06:00
Chris Privitere
777eddafd8 Move from env vars to github contexts.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-11 15:08:05 -06:00
Chris Privitere
0d5a140f0d Rename to docker since it's also building.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-11 15:07:19 -06:00
Daniel Finneran
4b269dcdfd Merge pull request #348 from cprivite/cprivite/issue342
Don't check interface is up if it's loopback.
2022-01-10 17:51:47 +00:00
Chris Privitere
1a4465ebcc Don't check interface is up if it's loopback.
Signed-off-by: Chris Privitere <cprivite@users.noreply.github.com>
2022-01-10 11:22:54 -06:00
Daniel Finneran
41dc5e9914 Merge pull request #347 from yaocw2020/main
Build and publish the main image every day
2022-01-07 09:57:29 +00:00
yaocw2020
c037ac3561 Build and publish the main image every day
Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2022-01-07 00:52:47 +08:00
Daniel Finneran
056a6c5c16 Update readme with correct URL for logo 2021-12-23 10:23:56 +00:00
Daniel Finneran
ec0014d9ea Add logo 2021-12-23 10:23:05 +00:00
Daniel Finneran
ce37958c39 Merge pull request #341 from yaocw2020/debugLog
set route event log as debug level
2021-12-22 15:49:39 +00:00
yaocw2020
98f0a9505b set route event log as debug level
Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2021-12-22 22:46:26 +08:00
Daniel Finneran
36f1b33e94 Merge pull request #338 from mrueg/manifests-0.4.1
docs: Generate manifests for 0.4.1
2021-12-22 13:31:55 +00:00
Daniel Finneran
bad7b5f92c Merge pull request #339 from yaocw2020/checkDefaultIF
Monitor default VIP interface
2021-12-22 13:31:31 +00:00
Daniel Finneran
ac6cbad0eb Merge pull request #340 from mrueg/common-labels
config: Use recommended labels in manifests
2021-12-22 13:20:46 +00:00
Manuel Rüger
afd9029474 config: Use recommended labels in manifests
https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/

Fixes: https://github.com/kube-vip/kube-vip/issues/315

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2021-12-22 13:52:32 +01:00
yaocw2020
306ce2440e Monitor default VIP interface
The kube-vip chooses the default interface based on the default
route. Once the default route changes, the default interface may be
invalid. In this case, it would be better to crash the process. The pod
will restart immediately if the kube-vip is deployed as a daemonset.

Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2021-12-22 20:37:58 +08:00
Manuel Rüger
0f391a0032 docs: Generate manifests for 0.4.1
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2021-12-22 13:32:38 +01:00
Daniel Finneran
94ab16575f Merge pull request #337 from thebsdbox/new_release
New 0.4.1 release
2021-12-22 11:35:16 +00:00
thebsdbox
179cfef6e2 New 0.4.1 release 2021-12-22 11:06:55 +00:00
Daniel Finneran
fdf7773d29 Merge pull request #334 from mrueg/update
Update golang to 1.16.12 and golang dependencies
2021-12-22 10:44:32 +00:00
Daniel Finneran
2e554c9d49 Merge pull request #336 from thebsdbox/SYS_TIME
removes an incorrect CAP
2021-12-22 10:44:16 +00:00
thebsdbox
3507c46a51 Removes redundant config generation and e2e fix 2021-12-22 10:25:19 +00:00
thebsdbox
7f58bf4012 removes an incorrect CAP 2021-12-22 10:14:20 +00:00
Manuel Rüger
cd5fa620d5 pkg/vip/ndp.go: Rename Dial to Listen
Function was renamed.
See: 9dc889e435

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2021-12-22 00:37:28 +01:00
Manuel Rüger
19d84bb50b go.mod: Update dependencies
github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 -> v0.8.0
github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e -> v0.0.0-20211214070828-5297eed8f489
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 -> v0.0.0-20210831201139-f982b8766fb5
github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf -> v0.0.0-20211126142749-4eae47f3d54b
github.com/onsi/ginkgo v1.14.0 -> v1.14.2
github.com/packethost/packngo v0.13.0 -> v0.20.0
github.com/prometheus/client_golang v0.10.0 -> v0.11.0
github.com/spf13/cobra v1.1.3 -> v1.3.0
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f -> v0.0.0-20211101163701-50045581ed74
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d -> v0.0.0-20211216030914-fe4d6282115f
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 -> v0.0.0-20211216021012-1d35b9e2eb4e
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 -> v0.0.0-20210927222741-03fcf44c2211
k8s.io/api v0.22.2 -> v0.22.5
k8s.io/apimachinery v0.22.2 -> v0.22.5
k8s.io/client-go v0.22.2 -> v0.22.5
k8s.io/klog/v2 v2.9.0 -> v2.40.1
sigs.k8s.io/kind v0.10.0 -> v0.11.1

Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2021-12-22 00:37:28 +01:00
Manuel Rüger
09088a9c17 Dockerfile: Update to go 1.16.12 and alpine 3.15 base
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
2021-12-21 23:22:03 +01:00
Daniel Finneran
a5b0eab318 Adding static analysis as part of CNCF onboarding 2021-12-21 09:33:52 +00:00
Daniel Finneran
1deb91a93d Merge pull request #332 from thebsdbox/vip_services_doc
Adds missing flag/env for services interface
2021-12-20 13:21:55 +00:00
thebsdbox
dd621131c6 Adds missing flag/env for services interface 2021-12-20 13:11:35 +00:00
Daniel Finneran
f442e61fd3 Merge pull request #329 from yaocw2020/validateInterface
Check interface
2021-12-19 11:22:33 +00:00
yaocw2020
df539cbc6e Check interface
In some cases, kube-vip will start to serve before the interface is not
existed or not up. We should make sure the interface is valid.

Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2021-12-17 00:02:18 +08:00
Daniel Finneran
1d39a5b34a Merge pull request #326 from spectrocloud/ddns-fix
fix ddns support
2021-12-13 11:52:39 +00:00
Deepak Sharma
a642f32414 add client id to request
Signed-off-by: Deepak Sharma <deepak@spectrocloud.com>
2021-12-13 16:18:00 +05:30
Daniel Finneran
ccc97b9bc5 Merge pull request #327 from jbguerraz/lbforwardingtype
allow to configure the ipvs forwarding method
2021-12-13 09:11:20 +00:00
Jean-Baptiste Guerraz
0649fb01eb allow to configure the ipvs forwarding method 2021-12-11 23:21:13 +00:00
Deepak Sharma
3855ed4553 ddns fix
gofmt file

Signed-off-by: Deepak Sharma <deepak@spectrocloud.com>
2021-12-10 17:03:47 +05:30
Daniel Finneran
3979c1fcce Merge pull request #320 from lewisdiamond/patch-3
Fix typo in log (s/addded/added/)
2021-12-06 12:42:55 +00:00
Daniel Finneran
af52f4f9fd Merge pull request #323 from sykesm/address-no-vip-panic
Pass resolved VIP from Network.IP() to NewIPVSLB
2021-12-06 12:42:05 +00:00
Daniel Finneran
4e1bb7f77a Merge pull request #321 from sykesm/control-plane-label
Update label selector for control-plane nodes
2021-12-02 11:19:22 +00:00
Lewis Diamond
92f6ad4395 Fix typo in log (s/addded/added/)
Signed-off-by: Lewis Diamond <git@lewisdiamond.com>
2021-11-29 11:27:31 -05:00
Matthew Sykes
2d14d63ef2 Pass resolved VIP from Network.IP() to NewIPVSLB
When the manager process is started without the `--vip` flag, it will
panic during initialization. This is because the `nil` result from
`net.ParseIP("")` is passed to `ipvs.NewIP()`.

This change passes the resolved address from `cluster.Network.IP()`
instead of the possibly-empty VIP from the configuration.

Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>
2021-11-27 21:16:38 -05:00
Matthew Sykes
022b62caca Update label selector for control-plane nodes
The current node watcher uses a label selector of the form
`node-role.kubernetes.io/control-plane=`; this does not work correctly.

The label selector should be `node-role.kubernetes.io/control-plane" or
`node-role.kubernetes.io/control-plane=true` to select the control-plane
nodes.

Without these changes, the IPVS tables are never updated with the
control plane nodes and clients making requests to the VIP will fail
with a "connection refused" error.

```
$ kubectl get nodes -l node-role.kubernetes.io/control-plane=
No resources found

$ kubectl get nodes -l node-role.kubernetes.io/control-plane=true
NAME     STATUS   ROLES                       AGE   VERSION
pi4-00   Ready    control-plane,etcd,master   21h   v1.22.3+k3s1
pi4-01   Ready    control-plane,etcd,master   20h   v1.22.3+k3s1
pi4-02   Ready    control-plane,etcd,master   20h   v1.22.3+k3s1

$ kubectl get nodes -l node-role.kubernetes.io/control-plane
NAME     STATUS   ROLES                       AGE   VERSION
pi4-00   Ready    control-plane,etcd,master   21h   v1.22.3+k3s1
pi4-01   Ready    control-plane,etcd,master   20h   v1.22.3+k3s1
pi4-02   Ready    control-plane,etcd,master   20h   v1.22.3+k3s1
```

Signed-off-by: Matthew Sykes <matthew.sykes@gmail.com>
2021-11-27 14:00:01 -05:00
Daniel Finneran
2a2cb7b5fa Update index.md 2021-11-25 09:45:27 +00:00
Daniel Finneran
0783c006b8 Update index.md
Fixes header
2021-11-25 09:44:43 +00:00
Daniel Finneran
147ae7ae5f Merge pull request #316 from thebsdbox/ipvs_race_condition
IPVS fixes
2021-11-23 19:19:31 +00:00
Daniel Finneran
0a3f963578 Merge pull request #313 from chipzoller/main
Extensive linting, corrections, expansions
2021-11-23 19:19:19 +00:00
Chip Zoller
48fc7bd4a1 Merge branch 'main' into main 2021-11-23 10:22:11 -05:00
Chip Zoller
8ad1620844 fix conflicts
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-23 10:20:29 -05:00
Chip Zoller
a36d33e4e5 further edits; revamp K3s docs
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-23 10:17:26 -05:00
thebsdbox
135a6b55e2 Final fixes to IPVS 2021-11-23 15:17:24 +00:00
Daniel Finneran
17fd21aeda Merge pull request #317 from lewisdiamond/patch-2
Various KIND documentation fixes
2021-11-23 15:02:24 +00:00
Lewis Diamond
0b6d0be44b Various KIND documentation fixes
KVVERSION needs to be preceeded with `$` for shell expansion of the variable.
`kubectl` is unlikely to be a binary in the current directory and is likely to be in `$PATH`
2021-11-22 16:55:09 -05:00
thebsdbox
82db862a1a IPVS fixes 2021-11-22 20:00:05 +00:00
Chip Zoller
6f18708ec2 address PR comments
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-22 12:25:27 -05:00
Chip Zoller
c1c9635bf4 updates
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-22 10:06:25 -05:00
Chip Zoller
f5e8e05271 more work
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-22 09:17:17 -05:00
Chip Zoller
2ec0510a37 more linting
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-21 20:01:31 -05:00
Chip Zoller
31e4958c99 linting
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-21 19:39:17 -05:00
Chip Zoller
a377b6e2a8 linting, typos
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-21 19:32:04 -05:00
Chip Zoller
f5a2bd8e59 Extensive linting, corrections, expansions
Signed-off-by: Chip Zoller <chipzoller@gmail.com>
2021-11-21 19:23:00 -05:00
Daniel Finneran
88d6df058b Merge pull request #308 from thebsdbox/custom_ipvs_port
Allows setting an API server port
2021-11-10 16:37:29 +00:00
thebsdbox
b11b9ba396 Allows setting an API server port 2021-11-10 15:59:35 +00:00
Daniel Finneran
4585812e0e Merge pull request #306 from thebsdbox/0.4-release
New release v0.4.0
2021-11-09 13:26:52 +00:00
thebsdbox
7b79084ae2 New release v0.4.0 2021-11-09 13:01:23 +00:00
Daniel Finneran
fd61ee4d49 Merge pull request #305 from thebsdbox/more_docs
Fix manifests and old generator
2021-11-09 12:56:18 +00:00
Daniel Finneran
e190256f92 Merge pull request #303 from thebsdbox/code_dedupe
Removes duplicated code and tidies function names
2021-11-09 12:56:02 +00:00
thebsdbox
4c1fd117d5 Fix manifests and old generator 2021-11-09 12:53:41 +00:00
Daniel Finneran
6ffa87e42b Merge pull request #304 from thebsdbox/0.4docs
Docs for upcoming 0.4 release
2021-11-09 11:44:06 +00:00
Daniel Finneran
1c73f15bef Merge branch 'main' into 0.4docs 2021-11-09 11:43:42 +00:00
thebsdbox
27e889e8a6 Docs for upcoming 0.4 release 2021-11-09 11:42:07 +00:00
thebsdbox
a75a53c47e lint fix ! 2021-11-08 12:21:31 +00:00
thebsdbox
c0a5c7a762 Removal of more duplicate code 2021-11-08 12:17:53 +00:00
thebsdbox
35f7d816f4 Removes duplicated code and tidies function names 2021-11-07 14:56:48 +00:00
Daniel Finneran
cfc6aa04ba Merge pull request #302 from RZRCDR/main
Add hostAliases to kube-vip-arp-ds.yaml on v0.3.9
2021-11-06 14:26:57 +00:00
Daniel Finneran
259091d019 Merge pull request #301 from shibumi/shibumi/update-image
update images
2021-11-02 09:18:48 +00:00
Dirkco du Plessis
0cef76ff4a Add hostAliases to kube-vip-arp-ds.yaml on v0.3.9
Signed-off-by: Dirkco du Plessis <dduplessis@credogroup.com>
2021-10-30 12:02:41 +01:00
Christian Rebischke
a79d5e61e9 update images
Signed-off-by: Christian Rebischke <chris@shibumi.dev>
2021-10-30 03:29:32 +02:00
Daniel Finneran
066c046cf5 Merge pull request #296 from thebsdbox/ipvs
Replace IPVS as the API server LoadBalancer
2021-10-28 15:54:51 +01:00
thebsdbox
08d38f5520 Final fixes to the IPVS work 2021-10-26 15:03:00 +01:00
thebsdbox
81975220c6 Fixed missing import 2021-10-26 13:52:25 +01:00
Daniel Finneran
93cca8e938 Merge branch 'main' into ipvs 2021-10-26 13:48:26 +01:00
thebsdbox
e1bfcb1aa6 Tidying up of redundant code, fixes to fwdtype lb 2021-10-26 13:47:13 +01:00
Daniel Finneran
8a05989122 Merge pull request #298 from stevesloka/refactork8sClient
Refactor the Kubernetes client generation into a single package
2021-10-26 13:32:10 +01:00
Steve Sloka
9b65c1e63c Refactor the Kubernetes client generation into a single place inside a new k8s package.
Signed-off-by: Steve Sloka <slokas@vmware.com>
2021-10-25 15:30:23 -04:00
Daniel Finneran
e4ab718bc9 Merge pull request #297 from mikenabhan/patch-1
Fix spelling in documentation
2021-10-25 08:56:32 +01:00
Mike Nabhan
cf122a3239 Fix spelling in documentation 2021-10-24 18:03:38 -06:00
thebsdbox
6c759fcd74 Lint fixes 2021-10-22 15:53:59 +01:00
thebsdbox
7a759e41f7 Replace IPVS as the API server LoadBalancer 2021-10-22 09:28:41 +01:00
Daniel Finneran
a35df41b46 Merge pull request #294 from thebsdbox/leaderElection
Removes local leaderElection fix
2021-10-20 17:30:23 +01:00
thebsdbox
843c3ebf94 Removes local leaderElection fix 2021-10-20 17:21:12 +01:00
Daniel Finneran
638c521d36 Merge pull request #295 from kube-vip/thebsdbox-patch-1
Update ci.yaml
2021-10-20 17:18:25 +01:00
Daniel Finneran
e2e2183e57 Update ci.yaml
Moves from Go 1.15 to 1.16
2021-10-20 17:09:41 +01:00
Daniel Finneran
65363c21ec Merge pull request #291 from thebsdbox/ignore_service
Ability for Kube-Vip to ignore a service
2021-10-20 15:55:18 +01:00
Daniel Finneran
903a341873 Merge branch 'main' into ignore_service 2021-10-20 15:46:54 +01:00
Daniel Finneran
b544e5b729 Merge pull request #290 from stevesloka/fixupLintErrors
Adds golangci-lint to check for code errors + clean up resulting findings
2021-10-20 15:46:10 +01:00
Daniel Finneran
c140e6afa5 Merge pull request #292 from kube-vip/Adds-golangci-lint
Update ci.yaml
2021-10-20 15:17:38 +01:00
Daniel Finneran
2cd9b36fac Update ci.yaml 2021-10-20 15:08:09 +01:00
Steve Sloka
2e9c2244c1 Adds golangci-lint to check for code errors + clean up resulting findings after running.
Signed-off-by: Steve Sloka <slokas@vmware.com>
2021-10-20 13:55:34 +00:00
thebsdbox
ec6fbfd162 Fixes order for reading env vars, and ignore svc 2021-10-20 14:53:19 +01:00
Daniel Finneran
70f14a5bfd Merge pull request #289 from thebsdbox/main
Auto detect default interface for VIP
2021-10-19 16:04:58 +01:00
thebsdbox
821a488e15 Removed autoInterface option 2021-10-19 14:34:54 +01:00
thebsdbox
0d492faaf0 Auto detect default interface for VIP 2021-10-19 11:17:33 +01:00
Daniel Finneran
c94c15a6b9 Merge pull request #285 from thebsdbox/localhost
Use localhost to connect to manager
2021-10-13 11:10:37 +01:00
thebsdbox
e2c8e4d724 Automates the changes required for callback to API server 2021-10-13 10:48:17 +01:00
thebsdbox
1f7ff01bec Use localhost to connect to manager 2021-10-12 11:41:44 +01:00
Daniel Finneran
53ac3868e8 Merge pull request #284 from thebsdbox/testing_fix
Adds easier moving between Kubernetes versions
2021-10-12 10:50:01 +01:00
thebsdbox
74fa77735b Adds easier moving between Kubernetes versions 2021-10-12 10:49:08 +01:00
Daniel Finneran
9f244e4d7d Merge pull request #278 from larrymapacket/larry-kubevip
update Metal's doc
2021-10-08 14:23:36 +01:00
larrymapacket
a46042e548 update the Equinix Metal kube-vip doc.
Signed-off-by: larrymapacket <larry@packet.com>
2021-10-04 17:09:57 -05:00
larrymapacket
0c82f3e00b Changing EquiniMetal usage document to add a few missing information and links.
Signed-off-by: larrymapacket <larry@packet.com>
2021-09-28 17:09:54 -05:00
Daniel Finneran
c333e2a1eb Merge pull request #274 from elmariofredo/patch-1
Add link to Equinix Metal  metal-gateway guide
2021-09-18 09:51:36 +01:00
Mario Vejlupek
96c7dc5f15 Add link to Equinix Metal metal-gateway guide
Signed-off-by: Mario Vejlupek <mario@vejlupek.cz>
2021-09-16 09:47:10 +02:00
Daniel Finneran
6bfed9c454 Merge pull request #272 from detiber/bumpgobgp 2021-09-10 21:39:00 +02:00
Jason DeTiberus
975b892e6d Bump gobgp dependency to the latest v2.31.0
Signed-off-by: Jason DeTiberus <detiber@users.noreply.github.com>
2021-09-10 14:07:03 -04:00
Daniel Finneran
ab19d4a4a4 Merge pull request #266 from thebsdbox/nic_seperation 2021-09-04 15:03:24 +02:00
thebsdbox
5f751cc321 Fixes from feedback 2021-09-03 13:37:43 +01:00
Daniel Finneran
59ce702b5e Merge pull request #268 from detiber/creds 2021-09-02 22:37:27 +02:00
Jason DeTiberus
7bfa79750d Support use Equinix Metal credentials from config
Use Equinix Metal credentials when available with EIP configuration
not just BGP configuration.

Signed-off-by: Jason DeTiberus <detiber@users.noreply.github.com>
2021-09-02 16:21:19 -04:00
Daniel Finneran
2ec44596b3 Merge pull request #267 from detiber/nodeAffinity
Update DaemonSet generation to improve scheduling
2021-09-02 21:28:10 +02:00
Jason DeTiberus
9addea6149 Update DaemonSet generation to improve scheduling
- Tolerate more than just the node-role.kubernetes.io/master taint, this allows
  the daemonset to schedule prior to CNI being deployed.

- Switch from using a nodeSelector to using nodeAffinity
  - Allows scheduling even if the node label does not match the value (for the node-role label, the value is generally ignored).
  - Add support for the control-plane node role rather than just master.

Signed-off-by: Jason DeTiberus <detiber@users.noreply.github.com>
2021-09-02 14:09:23 -04:00
thebsdbox
d06176a56b Implements a secondary interface just for services 2021-09-02 10:07:17 +01:00
Daniel Finneran
cc0fe1e870 Merge pull request #265 from thebsdbox/src_annotation
This will set source IP for BGP from annotations
2021-09-01 16:41:15 +02:00
thebsdbox
306a75ff84 This will set source IP for BGP from annotations 2021-09-01 14:53:55 +01:00
Daniel Finneran
3e565851e8 Merge pull request #264 from thebsdbox/docs_fix
Fixes Docs
2021-09-01 10:52:13 +02:00
thebsdbox
0a57816567 Fixes Docs 2021-09-01 09:51:00 +01:00
Daniel Finneran
8021ef7bf6 Updates Makefile to correct version 2021-09-01 09:42:11 +01:00
Daniel Finneran
3cc6b17916 Merge pull request #263 from detiber/useProjectID
[metal] Use provided provider id in config if defined
2021-09-01 10:13:22 +02:00
Jason DeTiberus
925b3bdc20 [packet] Support Address config in addition to VIP
Signed-off-by: Jason DeTiberus <detiber@users.noreply.github.com>
2021-08-31 18:20:57 -04:00
Jason DeTiberus
4a814f2427 [metal] Use provided provider id in config if defined
Signed-off-by: Jason DeTiberus <detiber@users.noreply.github.com>
2021-08-31 17:34:15 -04:00
Daniel Finneran
b72c984d5c Merge pull request #262 from thebsdbox/password_bug
Fixes the broken logic in password parsing
2021-08-31 18:34:34 +02:00
thebsdbox
fab9be29f0 Fixes the broken logic in password parsing 2021-08-31 17:18:16 +01:00
Daniel Finneran
a93b8382ac Merge pull request #261 from thebsdbox/BGP_Source
This change allows to specify either an adapter on an address to peer from
2021-08-26 13:14:55 +02:00
thebsdbox
54615fa750 Remove duplicate flag 2021-08-25 16:00:51 +01:00
thebsdbox
2b0345cc86 Adds BGP Source 2021-08-25 15:58:11 +01:00
Daniel Finneran
165b2ebb40 Merge pull request #255 from kplimack/advertise 2021-08-17 06:49:23 +01:00
Jake Plimack
9188f554ab spelling
Signed-off-by: Jake Plimack <jplimack@tesla.com>
2021-08-16 18:05:44 -06:00
Daniel Finneran
c92bec91b7 Merge pull request #253 from panpan0000/fix_ServiceType
fix typo of ServiceType. There's no svc.spec.type = ServiceTypeLoadBalancer
2021-08-05 08:30:47 +01:00
panpan0000
a42a5e7493 fix typo of ServiceType 2021-08-05 02:19:14 -04:00
Daniel Finneran
c46887c0bc Merge pull request #249 from rawkode/fix/annotations-first-pass
fix: ensure node annotations are checked before watch
2021-07-26 11:45:27 +01:00
David McKay
76dbce050c chore: add tests for parseBgpAnnotations 2021-07-26 11:33:02 +01:00
David McKay
7c644d680d chore: use node ResourceVersion 2021-07-26 11:01:40 +01:00
David McKay
fc24064e2a fix: ensure node annotations are checked before watch 2021-07-26 09:40:25 +01:00
Daniel Finneran
092eb5423a Merge pull request #248 from rawkode/chore/use-ghcr-default 2021-07-24 21:45:32 +01:00
David McKay
a26288a1d0 chore: encourage useage of GHCR instead of rate limited Docker Hub 2021-07-24 16:53:57 +01:00
David McKay
39043ce0f8 fix: backticks are deprecated and not POSIX compat, replace with $() 2021-07-24 16:35:11 +01:00
David McKay
31448255e8 chore: use git to fetch latest tag 2021-07-24 16:34:37 +01:00
Daniel Finneran
976d2f64fb Update Makefile 2021-07-23 17:52:51 +01:00
Daniel Finneran
0e751402eb Merge pull request #245 from mkumatag/support_ppc64le
Add support for ppc64le architecture
2021-07-23 09:08:55 +01:00
Manjunath A Kumatagi
df8a3addc1 Add support for ppc64le architecture 2021-07-23 09:38:35 +05:30
Daniel Finneran
aa155cd7d5 Update index.md 2021-07-21 15:43:59 +01:00
Daniel Finneran
81f7338dbd Update index.md 2021-07-21 15:42:43 +01:00
Daniel Finneran
cb6d8ac1a7 Merge pull request #237 from abhinavmpandey08/main 2021-07-12 17:57:02 +01:00
Abhinav Pandey
c395d45200 Add example manifest for kube-vip:v0.3.5 2021-07-12 09:01:33 -07:00
Daniel Finneran
8a64752585 Merge pull request #236 from thebsdbox/VIP_race
Fixes re-application of VIP
2021-07-09 17:00:04 +01:00
thebsdbox
27451767c3 Fixes re-application of VIP 2021-07-09 11:37:47 +01:00
Daniel Finneran
2d37e0e8df Merge pull request #229 from yaocw2020/main
Refactor the DHCP client
2021-07-07 09:59:46 +01:00
yaocw2020
e906270eb2 Refactor the DHCP client
Signed-off-by: yaocw2020 <yaocanwu@gmail.com>
2021-07-07 12:19:11 +08:00
Daniel Finneran
de5ca6a88e Merge pull request #232 from thebsdbox/kind_doc
Adds documentation for KIND
2021-07-06 17:22:22 +01:00
thebsdbox
ad43fa3202 Adds documentation for KIND 2021-07-06 17:16:30 +01:00
Daniel Finneran
d7078a89e2 Create CODEOWNERS 2021-07-06 15:44:07 +01:00
Daniel Finneran
1ede20f457 Merge pull request #227 from thebsdbox/annotations_bug
Fixes the hang on BGP password
2021-07-06 14:31:58 +01:00
Daniel Finneran
478e0d6ac9 Merge pull request #231 from thebsdbox/docs_rewrite
Big docs re-org
2021-07-06 14:31:47 +01:00
thebsdbox
f682535990 Final re-arrange of lb docs 2021-07-06 13:53:35 +01:00
thebsdbox
090182bcc8 BGP router_ID 2021-07-06 13:44:32 +01:00
thebsdbox
f19deede30 Big docs re-org 2021-07-06 13:12:48 +01:00
thebsdbox
9273a7d9e4 Fixes the hang on BGP password 2021-07-05 13:38:40 +01:00
Daniel Finneran
bba0906293 Merge pull request #222 from rawkode/fix/bgp-broadcast-error 2021-06-24 19:53:22 +03:00
David McKay
b24723ea7a fix: propagate errors when broadcasting BGP address fails 2021-06-24 16:28:25 +01:00
Daniel Finneran
2a6faaa37b Merge pull request #219 from thebsdbox/Makefile
Fixes manifest generation
2021-06-18 14:23:09 +01:00
thebsdbox
6e2495b9a1 Fixes manifest generation 2021-06-18 14:13:29 +01:00
Daniel Finneran
edfec80d03 Merge pull request #218 from sammcgeown/main
Update CCM docs and manifest
2021-06-17 20:09:08 +01:00
Sam McGeown
98803b4d74 Update kube-vip services docs with latest kube-vip details 2021-06-17 15:17:52 +01:00
Sam McGeown
aa39904040 Update CCM controller manifest to match kube-vip-cloud-controller repository 2021-06-17 14:15:38 +01:00
Daniel Finneran
deb2276e3e Merge pull request #212 from onedr0p/patch-1 2021-05-28 13:04:43 +01:00
ᗪєνιη ᗷυнʟ
a9286fd8c3 feat: push images to ghcr 2021-05-28 07:59:22 -04:00
Daniel Finneran
a0b5e7720a Merge pull request #208 from tahaozket/patch-1
Update kube-vip.go
2021-05-18 16:51:46 +01:00
Taha Ozket
2f0e1eec47 Update kube-vip.go
typo fixed metalrojectID -> metalProjectID
2021-05-15 19:29:26 +03:00
Daniel Finneran
94e8984ed1 Create CONTRIBUTING.md 2021-05-14 14:07:37 +01:00
Daniel Finneran
79f0fb9283 Create CODE_OF_CONDUCT.md 2021-05-14 12:55:21 +01:00
Daniel Finneran
318eaca208 Merge pull request #206 from kube-vip/Roadmap
Create ROADMAP.md
2021-05-14 12:41:31 +01:00
Daniel Finneran
1efc24d712 Create ROADMAP.md 2021-05-14 09:39:45 +01:00
Daniel Finneran
2cedaff8be Merge pull request #205 from thebsdbox/ddns
Fixes DDNS
2021-05-13 17:11:39 +01:00
thebsdbox
5545471391 Fixes DDNS 2021-05-13 17:10:44 +01:00
Daniel Finneran
874a0bb6d1 Merge pull request #203 from thebsdbox/dhcp_swap
Swap DHCP to a pkg with better licenses
2021-05-13 16:43:27 +01:00
thebsdbox
f69d0b77f6 Complete re-write of dhcp 2021-05-13 14:02:38 +01:00
thebsdbox
927ddf74fb Swap DHCP to a pkg with better licenses 2021-05-07 15:55:25 +01:00
Daniel Finneran
cb8cf78234 Merge pull request #200 from franciosi/patch-2
Small Typo Improves in README.md
2021-04-27 10:17:46 +01:00
Franciosi
eaebadd668 Small Typo Improves in README.md
Small typo improvements
2021-04-26 15:54:46 -03:00
Daniel Finneran
f234a6b7fe Merge pull request #199 from thebsdbox/error_fix
Error fixes
2021-04-21 19:32:38 +01:00
thebsdbox
49b77ab303 Error fixes 2021-04-21 19:31:40 +01:00
Daniel Finneran
49c5821508 Merge pull request #198 from thebsdbox/interface_fix
Fixes interface on networking restart
2021-04-21 08:40:41 +01:00
thebsdbox
239ff56dfa Fixes interface on networking restart 2021-04-20 15:25:32 +01:00
Daniel Finneran
00572acbc1 Update README.md 2021-04-20 11:04:52 +01:00
Daniel Finneran
afffb41d5d Merge pull request #197 from rosenhouse/e2e-action
run e2e tests in CI
2021-04-20 09:05:06 +01:00
Daniel Finneran
2af456b66f Merge pull request #196 from thebsdbox/BGP_PASSWORD
Bgp password support from annotations.
2021-04-20 09:04:51 +01:00
Gabe Rosenhouse
9fdf8026dd run e2e tests in CI 2021-04-19 21:58:58 +00:00
thebsdbox
e1d3ee24ea base64 decoding 2021-04-19 13:55:38 +01:00
thebsdbox
f1553b2bcd Adds Password support 2021-04-19 13:51:38 +01:00
Daniel Finneran
30f1c44223 Merge pull request #195 from anagno/actions
Adding the release actions
2021-04-19 09:39:58 +01:00
Vasileios Anagnostopoulos
e304614f35 Adding the release actions 2021-04-17 00:43:22 +02:00
Daniel Finneran
a020fb180d Merge pull request #185 from flawedmatrix/ipv6-neighbor-advertisement
Initial Support IPv6
2021-04-15 14:24:22 +01:00
Daniel Finneran
2d29c6fe12 Merge pull request #193 from smira/fix-equinix-ip-unassign
fix: unassign IPs correctly for Equinix Metal
2021-04-15 13:41:42 +01:00
Andrey Smirnov
7c4d919cfc fix: unassign IPs correctly for Equinix Metal
IP assignment href returned from the API looks like:

```
/metal/v1/ips/97972920-f00b-453f-be1e-31eb53c19e38
```

It should be cleaned up to contain ID only, removing `/ips/` leads to
broken requests like:

```
2021/04/15 12:03:41 [DEBUG] DELETE https://api.equinix.com/metal/v1/ips//metal/v197972920-f00b-453f-be1e-31eb53c19e38
```

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
2021-04-15 15:33:58 +03:00
Daniel Finneran
5a32bd5392 Merge pull request #192 from splashx/patch-1
change word expended to expanded
2021-04-13 13:50:37 +01:00
Diogenes S. Jesus
3cf9702077 change word expended to expanded
"expend" => "spend"
"expand" => "become/make larger"
2021-04-13 14:46:59 +02:00
Edwin Xie
dbfc39cee3 Support IPv6
- Implement gratuitous NDP neighbor advertisements
- Add e2e tests for IPv6 neighbor advertisements and IPv4 ARP broadcasts
  - Adds a README.md for e2e tests
- Adds go.mod dependencies
  - Kind to run clusters
  - Ginkgo testing framework
  - Gomega assertion library
  - ndp library to help with NDP

Co-authored-by: Aidan Obley <aobley@vmware.com>
Co-authored-by: Gabriel Rosenhouse <grosenhouse@vmware.com>
2021-03-12 23:53:27 +00:00
Daniel Finneran
0a52356a74 Merge pull request #182 from thebsdbox/arp_fixes
Fixes to arp/controller and manifests
2021-03-08 17:31:59 +00:00
thebsdbox
6d1c60dae1 Fixes to arp/controller and manifests 2021-03-08 15:12:50 +00:00
Daniel Finneran
4c6fa47f51 Merge pull request #174 from gianarb/fix/manager_arp_return_value
Catch return value for StartLeaderCluster
2021-03-03 11:21:37 +00:00
Gianluca Arbezzano
3744f05adc Catch return value for StartLeaderCluster
Error handling for the function StartLeaderCluster is not properly done.

Signed-off-by: Gianluca Arbezzano <gianarb92@gmail.com>
2021-03-03 12:09:59 +01:00
Yassine TIJANI
2988c62df6 Merge pull request #170 from yastij/exit-onleaderstop
leaderelection exit when the election is lost
2021-02-18 21:05:35 +01:00
Yassine TIJANI
51122839a6 exit when the leaderelection is lost
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2021-02-18 16:46:51 +01:00
Daniel Finneran
a3444b60dd Update kube-vip-bgp-em-ds.yaml 2021-02-15 14:55:29 +00:00
Daniel Finneran
42d49d3087 Update kube-vip-bgp-em-ds.yaml 2021-02-15 14:55:15 +00:00
Daniel Finneran
b9a3da4933 Merge pull request #168 from displague/patch-1
fix "services" typo in hybrid docs
2021-02-04 19:53:03 +00:00
Marques Johansson
ea5e24b31f fix "services" typo in hybrid docs 2021-02-04 11:26:32 -05:00
Daniel Finneran
72d961969f Update index.md 2021-02-04 09:19:24 +00:00
Daniel Finneran
6ab79210aa Merge pull request #167 from plunder-app/fix/learn-how-to-use-labels-again
Fix label grouping with Prometheus
2021-02-03 18:31:17 +00:00
Gianluca Arbezzano
5061c55298 Fix label grouping with Prometheus 2021-02-03 18:53:31 +01:00
Daniel Finneran
ba80734fea Merge pull request #166 from plunder-app/hotfix/prom-namespace-no-dash
Fix the namespace for prometheus metrics
2021-02-03 17:01:37 +00:00
Gianluca Arbezzano
72fcf743b1 Fix the namespace for prometheus metrics 2021-02-03 17:57:23 +01:00
Daniel Finneran
c3ea3888af Merge pull request #164 from plunder-app/feat/init-prom-metrics
Add prometheus support
2021-02-03 16:37:35 +00:00
Gianluca Arbezzano
d799eb06e4 Add counter for service events
This commit adds a Prometheus counter that counts the number of events
fired by the watcher grouped by event type
2021-02-03 17:29:51 +01:00
Daniel Finneran
b5f5bb47df Update index.md 2021-02-03 13:34:06 +00:00
Daniel Finneran
b911b3f2e2 Merge pull request #165 from thebsdbox/configname
Fixes packet -> metal
2021-02-03 13:26:17 +00:00
Daniel Finneran
3491fe8e93 Update index.md 2021-02-03 13:22:20 +00:00
thebsdbox
a26af37c5d Fixes packet -> metal 2021-02-03 11:40:30 +00:00
Gianluca Arbezzano
45c704f5c8 Initialise Prometheus http endpoint
This commit bootstrap the Prometheus endpoint.

By default an HTTP server starts using port 2112.
2021-02-01 12:47:12 +01:00
Daniel Finneran
e2f8628211 Update index.md 2021-01-27 10:22:20 +00:00
Daniel Finneran
1f4716e6af Merge pull request #162 from rawkode/feat/peer-ip-equinix-metal
fix: handle multiple peer-ips from ccm
2021-01-27 10:11:02 +00:00
David McKay
0d5341aab9 fix: handle multiple peer-ips from ccm 2021-01-26 17:29:03 +00:00
Daniel Finneran
157c105f38 Merge pull request #159 from thebsdbox/automation
Auto generate docs and manifests
2021-01-25 12:59:43 +00:00
Daniel Finneran
2fe1b1bdd0 Merge pull request #157 from thebsdbox/annotations
Annotations watcher
2021-01-25 12:52:58 +00:00
Daniel Finneran
e3c7716ae3 Merge pull request #157 from thebsdbox/annotations
Annotations watcher
2021-01-22 12:59:40 +00:00
thebsdbox
9870cc1e69 Cleaner details for deploying kube-vip on EM 2021-01-22 12:53:31 +00:00
thebsdbox
38d01b676b Move annotation lookup inside BGP startup 2021-01-22 12:21:12 +00:00
thebsdbox
a945113b3d Rename and docs update 2021-01-22 12:10:59 +00:00
thebsdbox
50945b85f5 Fixes to rbac and signals 2021-01-20 19:46:16 +00:00
thebsdbox
db9da78bff Annotaions watcher 2021-01-20 13:29:52 +00:00
Daniel Finneran
047b6b0f11 Merge pull request #156 from franciosi/patch-1
Update README.md
2021-01-05 20:48:54 +00:00
Franciosi
8570ae8310 Update README.md
Small typo fix
2021-01-05 17:02:45 -03:00
Daniel Finneran
22103ef857 Update index.md 2020-12-31 15:41:14 +00:00
Daniel Finneran
7cd9d9a654 Update index.md 2020-12-31 15:40:48 +00:00
Daniel Finneran
8d5a7b25d7 Update index.md 2020-12-31 15:39:28 +00:00
Daniel Finneran
b40e681f56 Merge pull request #152 from thebsdbox/address_fix
Fixes to testing and config
2020-12-31 11:56:43 +00:00
thebsdbox
52468cef64 Fixes to testing and config 2020-12-31 11:45:25 +00:00
Daniel Finneran
6ba899343a Merge pull request #150 from thebsdbox/serviceAccount_Fix
Fixes to serviceAccount
2020-12-26 17:27:02 +00:00
thebsdbox
792369ccb2 Fixes to serviceAccount 2020-12-26 17:22:09 +00:00
Daniel Finneran
7ebc75bd85 Merge pull request #149 from thebsdbox/vip_fix
Fixes missing address
2020-12-24 17:59:50 +00:00
thebsdbox
627ec8da3c final fix 2020-12-24 17:28:55 +00:00
thebsdbox
d89e8a5852 Fix workflow 2020-12-24 17:23:01 +00:00
thebsdbox
6dab4a4f35 Tidying of testing 2020-12-24 17:14:45 +00:00
Daniel Finneran
302f210bee Merge pull request #148 from thebsdbox/raw_cap
Fixes to capabilities and CI
2020-12-24 13:58:13 +00:00
thebsdbox
c68a86d7ac Docker build fix 2020-12-24 13:25:16 +00:00
thebsdbox
b0f53c69df go vet fixes 2020-12-24 13:21:50 +00:00
thebsdbox
94204c3d58 Makefile fix 2020-12-24 13:15:23 +00:00
thebsdbox
2e62ad98c2 Fixes to capabilities and CI 2020-12-24 09:46:02 +00:00
Daniel Finneran
3e0c58fbd9 Merge pull request #143 from mhuttner/patch-1
Fix documentation, kube-vip alias for containerd
2020-12-18 14:00:40 +00:00
Michael Huttner
13cc1cd995 Fix documentation, kube-vip alias for containerd
Fixes #142
2020-12-18 14:17:00 +01:00
Daniel Finneran
fbb7bf9a96 Update index.md 2020-12-18 10:43:02 +00:00
Daniel Finneran
22751059bf Update index.md 2020-12-18 10:41:18 +00:00
Daniel Finneran
93703e5535 Update index.md 2020-12-18 10:39:05 +00:00
Daniel Finneran
b1de378427 Merge pull request #141 from thebsdbox/taint_fix
Fixes to formatting and taint
2020-12-17 19:10:46 +00:00
thebsdbox
a8a44b9240 Fixes to formatting and taint 2020-12-17 19:10:14 +00:00
Daniel Finneran
eac9be40fc Merge pull request #140 from thebsdbox/final_fixes
Move to 0.3.0 and doc fixes
2020-12-17 17:53:49 +00:00
thebsdbox
325958c2a4 Move to 0.3.0 and doc fixes 2020-12-17 17:48:43 +00:00
Daniel Finneran
afdbac7a58 Merge pull request #124 from plunder-app/0.2.3
0.2.3 release
2020-12-17 17:36:34 +00:00
Daniel Finneran
be833041cb Merge pull request #139 from thebsdbox/etc_hosts
hostname_fix
2020-12-17 17:35:15 +00:00
thebsdbox
ad34e96627 hostname_fix 2020-12-17 16:27:07 +00:00
Daniel Finneran
5dc527699f Merge branch 'master' into 0.2.3 2020-12-17 15:54:43 +00:00
Daniel Finneran
13f5793cc1 Merge pull request #138 from thebsdbox/doc_update
This PR adds all of the updated documentation
2020-12-17 15:52:57 +00:00
thebsdbox
3271ccdfae Final bits of documentation 2020-12-17 15:49:29 +00:00
thebsdbox
564013bd14 Further doc updates, and serviceAccount Fix 2020-12-16 22:23:33 +00:00
Daniel Finneran
142f2a3ca5 Merge pull request #137 from gianarb/hotfix/permission-issue
Fix permission access in GitHub Action
2020-12-16 16:11:51 +00:00
thebsdbox
178142f0bd This PR adds all of the updated documentation 2020-12-16 16:08:54 +00:00
Gianluca Arbezzano
17cbd665cb Fix permission access in GitHub Action
I use `act` locally to run GitHub Action and apparently it works
differently and on GitHub you have to run apt as sudo.
2020-12-16 14:42:44 +01:00
Plunder
b78ecd5bc1 Merge pull request #136 from gianarb/ci/tests
Bootstrap continuous integration via GitHub Action
2020-12-16 13:12:32 +00:00
Gianluca Arbezzano
dc159b32d5 Fixed deprecated call to go vet and add go mod tidy
This commit migrates:

    $ go tools vet ./...

To

    $ go vet ./...

Because the first one triggers a deprecation warning.

It also adds a go mod tidy to validate that go mods are all right.
2020-12-16 13:33:29 +01:00
Gianluca Arbezzano
ff407ab606 Bootstrap CI for kube-vip on GitHub Action
This commit bootstraps a CI pipeline for kube-vip using GitHub action.
2020-12-16 13:33:29 +01:00
Daniel Finneran
db64064579 Merge pull request #134 from thebsdbox/multi_peers
Adds multiple peers from manifest
2020-12-15 19:50:23 +00:00
thebsdbox
058cfd7c09 Adds multiple peers from manifest 2020-12-15 19:45:57 +00:00
Plunder
92f01a7d00 Update issue templates 2020-12-15 13:56:41 +00:00
Plunder
568af564da Update bug_report.md 2020-12-15 13:56:00 +00:00
Plunder
e91ef9fc5c Update issue templates 2020-12-15 13:53:32 +00:00
Daniel Finneran
27dcdf691b Merge pull request #131 from thebsdbox/Dockerfile_fix_cacerts
Now uses projectID from env/cli
2020-12-14 18:30:11 +00:00
thebsdbox
3869c3520b Adds Dockerfile Fix 2020-12-14 18:29:49 +00:00
thebsdbox
38e0966fa6 Now uses projectID from env/cli 2020-12-11 20:46:43 +00:00
Daniel Finneran
bb7d2da73e Merge pull request #129 from thebsdbox/multi_hop_bgp
Multihop_and_use CCM Secret
2020-12-11 17:48:44 +00:00
thebsdbox
b8c40e926b Multihop_and_use CCM Secret 2020-12-11 17:44:53 +00:00
Daniel Finneran
2e2fd23c61 Merge pull request #128 from thebsdbox/multi_hop_bgp
Enables BGP multihop
2020-12-11 14:06:45 +00:00
thebsdbox
d3160001c4 Enables BGP multihop 2020-12-11 14:04:46 +00:00
Daniel Finneran
4636c8474a Merge pull request #127 from thebsdbox/ignore_vip_cp
Manifest for inCluster
2020-12-11 13:48:08 +00:00
thebsdbox
5e0add5737 inCluster manifest 2020-12-11 13:46:45 +00:00
Daniel Finneran
0144a5c481 Merge pull request #126 from thebsdbox/ignore_vip_cp
Fixes to manifest gen
2020-12-09 17:11:41 +00:00
thebsdbox
d5a618c244 Fixes to manifest gen 2020-12-09 17:10:30 +00:00
Daniel Finneran
3c357c4e2b Merge pull request #125 from thebsdbox/peer_password
This adds support for BGP Peer password
2020-12-08 20:57:27 +00:00
thebsdbox
879cfa7666 This adds support for BGP Peer password 2020-12-08 12:43:58 +00:00
Daniel Finneran
010247f0d2 Merge pull request #114 from thebsdbox/single_manager
First instance of a hybrid CP/SVCS design
2020-12-07 17:50:17 +00:00
thebsdbox
ddfc9e23a8 Hybrid mode is now implemented 2020-12-07 17:35:07 +00:00
thebsdbox
6e7a7a6dda Fixes to service deletion and errors 2020-12-06 16:50:00 +00:00
thebsdbox
a009f8a259 Moves the Status update to kube-vip 2020-12-04 18:46:40 +00:00
Daniel Finneran
505ffa84e6 Merge pull request #117 from plunder-app/0.2.2
0.2.2
2020-12-01 13:56:46 +00:00
Daniel Finneran
24c70ac7e2 Merge pull request #119 from thebsdbox/readme_fixes
Fixes to docs
2020-12-01 13:55:26 +00:00
thebsdbox
8930298f93 Fixes to docs 2020-12-01 13:54:45 +00:00
Daniel Finneran
dfda87e7ca Merge pull request #118 from thebsdbox/docs
Docs
2020-11-30 11:00:48 +00:00
thebsdbox
d28a49ca53 removes kube-vip binary before build 2020-11-30 10:59:27 +00:00
dan
4178a31de7 Ensures that BGP Manager isn't blocked cntrl plane 2020-11-26 19:11:41 +00:00
dan
06bc786caa Updated manifests and fixes to flags 2020-11-26 13:29:55 +00:00
dan
8b480c3688 Now will succesfully manage loadbalancers 2020-11-25 18:55:56 +00:00
dan
e02083d972 First instance of a hybrid CP/SVCS design 2020-11-24 18:08:33 +00:00
Daniel Finneran
2ea1295810 Merge pull request #113 from plunder-app/readme-update
Update README.md
2020-11-23 14:24:53 +00:00
Daniel Finneran
91645cbd36 Update README.md 2020-11-23 14:21:34 +00:00
Daniel Finneran
bd0ac71177 Merge pull request #111 from thebsdbox/interface_scope
Interface scope
2020-11-23 12:46:46 +00:00
Daniel Finneran
d780075622 Merge pull request #110 from thebsdbox/default_cidr
Default cidr
2020-11-23 12:39:29 +00:00
Daniel Finneran
0bdf1b5472 Merge pull request #109 from thebsdbox/master
BGP Fixes
2020-11-23 12:38:34 +00:00
dan
0241437a4f Fixes to scope 2020-11-20 19:47:01 +00:00
dan
8981de5f4f defaults the cidr for service types lb 2020-11-20 15:26:19 +00:00
dan
147f665054 BGP Fixes 2020-11-20 12:05:49 +00:00
Daniel Finneran
77d4cb8cd5 Merge pull request #104 from plunder-app/0.2.1
0.2.1
2020-11-13 13:11:36 +00:00
Daniel Finneran
ac52276e74 Merge pull request #106 from spectrocloud/ddns-doc
add docs for dns support
2020-11-13 09:59:33 +00:00
jzhoucliqr
6c056b441a add docs for dns support, also adding the missing ddns commandline option 2020-11-12 15:02:12 -08:00
Daniel Finneran
4a2a133779 Merge pull request #99 from spectrocloud/ddns
add dynamic dns support with dhcp for apiserver vip
2020-11-11 22:28:16 +00:00
jzhoucliqr
c5a4212229 add dynamic dns support with dhcp 2020-11-11 13:13:09 -08:00
thebsdbox
d93df4edb2 Fix to URLs 2020-11-11 13:53:18 +00:00
thebsdbox
38c42271f7 Doc re-write for 0.2.1 2020-11-11 13:44:09 +00:00
Daniel Finneran
fe060548a3 Merge pull request #103 from thebsdbox/logging_env
This fixes logging through env
2020-11-11 10:49:07 +00:00
thebsdbox
8afd5d50d4 This fixes logging through env 2020-11-11 10:48:14 +00:00
Daniel Finneran
95015b4d6b Merge pull request #102 from kaitoii11/master
Fix typo on README
2020-11-11 09:03:23 +00:00
Daniel Finneran
9495e8f106 Merge pull request #100 from thebsdbox/bgp_lb
This initial PR begins the work of using BGP as the load-balancer
2020-11-10 19:50:06 +00:00
thebsdbox
8f31390c80 Fixes the watcher for the lifecycle of the advertised address.
This final commit ensures that we stop advertising the VIP after the service is deleted
2020-11-10 15:16:25 +00:00
thebsdbox
051ed3d9eb Phase one BGP works
We can now create a BGP balanced load-balancer in Kubernetes.
2020-11-10 11:32:49 +00:00
Kaito Ii
b7dd13bf9f Merge pull request #1 from kaitoii11/readme-typo
Update README.md
2020-11-10 11:56:58 +09:00
Kaito Ii
31a5ca4d60 Update README.md 2020-11-10 11:56:36 +09:00
thebsdbox
71296c9c08 Fixes for existing DHCP interfaces
A macvlan interface is created using part of the service UUID, the service caching in the cloud-provider can cause problems with the same interface names.. This allows interface re-use.
2020-11-09 15:03:21 +00:00
thebsdbox
6c42cdf379 Rebase removed initialisation of upnp
This ensures that UPNP is started correctly, it was accidentally removed during the rebase.
2020-11-09 09:55:45 +00:00
thebsdbox
19757656b8 Tidy of code
This reduces repetition of environment variablers and re-uses the existing configuration builder.
2020-11-09 09:51:24 +00:00
thebsdbox
29c570eeb4 This PR begins the work of enabled BGP loadbalancing within a Kubernets cluster 2020-11-09 09:51:24 +00:00
Daniel Finneran
9977e30e29 Merge pull request #96 from thebsdbox/upnp
This adds upnp functionality to kube-vip
2020-11-09 09:41:56 +00:00
Daniel Finneran
564d9a3274 Merge pull request #98 from thebsdbox/lb_svc
LoadBalancer Service changes
2020-11-09 09:40:08 +00:00
thebsdbox
ca7a08bad1 Fixes to DHCP 2020-11-06 16:02:57 +00:00
Daniel Finneran
8968aa3f16 Merge pull request #94 from thebsdbox/docs
Adds documents into repo
2020-11-06 12:48:57 +00:00
thebsdbox
0eda56a44a Testing of new service 2020-11-06 10:00:07 +00:00
thebsdbox
8c44339757 This adds upnp functionality to kube-vip
With upnp functionality enabled any loadbalancer will be exposed through a upnp gateway!
2020-11-05 13:30:34 +00:00
Yassine TIJANI
8cc0973388 Merge pull request #95 from thebsdbox/int_fix
Fixes to int parsing
2020-11-04 13:47:12 +01:00
thebsdbox
ef7ace0400 Fixes to int parsing
I've no clue why the incorrect int parsing ended up in the code.
2020-11-04 12:23:19 +00:00
Daniel Finneran
850770dbaa Merge pull request #93 from dhawal55/make-port-configurable
Make port configurable
2020-11-03 19:41:43 +00:00
thebsdbox
4c3714223a Adds documents into repo 2020-11-02 20:19:16 +00:00
Dhawal Patel
66c733e55b Make port configurable 2020-11-02 11:32:33 -08:00
Daniel Finneran
47e32835bf Merge pull request #91 from thebsdbox/Makefile_bump
Bumps Makefile to new release
2020-10-28 17:27:15 +00:00
thebsdbox
de3c271318 Bumps Makefile to new release 2020-10-28 17:26:35 +00:00
Yassine TIJANI
87c2ab72bd Merge pull request #81 from spectrocloud/add-garp-request
send arprequest and arpreply alternatively for gratuitous arp
2020-10-28 18:07:51 +01:00
Yassine TIJANI
e3faef9413 Merge pull request #90 from yastij/fix-lookup
fix lookup ordering: check if it's an IP before assuming address is a DNS Name
2020-10-28 17:57:27 +01:00
Yassine TIJANI
e0aeda9e25 fix lookup ordering: check if it's an IP before assuming address is a DNS name
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-27 19:35:04 +01:00
jzhoucliqr
7c1df73cd5 send arprequest and arpreply alternatively for gratuitous arp 2020-10-23 12:38:16 -07:00
Daniel Finneran
444d22cf87 Merge pull request #89 from thebsdbox/podSpec
Fixes to pod/daemonset spec
2020-10-23 15:01:58 +01:00
thebsdbox
356949d9c9 Fixes to pod/daemonset spec 2020-10-23 15:01:31 +01:00
Yassine TIJANI
6f161eb061 Merge pull request #87 from plunder-app/0.1.9
0.1.9
2020-10-23 15:54:02 +02:00
Yassine TIJANI
b33e7da9f4 Merge pull request #84 from yastij/kube-vip-dns
DNS support for kube-vip
2020-10-19 15:58:05 +02:00
Yassine TIJANI
ec662cb24a only set ValidLft when address is a DNS Name
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 15:29:15 +02:00
Yassine TIJANI
3727d85fc1 re-use the existing IP in case of lookup failures
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 15:29:15 +02:00
Yassine TIJANI
6afc02240b plumb the DNS support
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 15:29:15 +02:00
Yassine TIJANI
d5734561c5 add the possibility to update the network
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 14:33:10 +02:00
Yassine TIJANI
d60d64f0a5 add the ip updater
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 14:33:10 +02:00
Yassine TIJANI
98f2757749 add checks the address flag
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 14:33:10 +02:00
Yassine TIJANI
2d9535eee4 add a new flag to enable DNS names and IPs
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>
2020-10-19 14:33:10 +02:00
Daniel Finneran
e529b64d88 Merge pull request #83 from thebsdbox/daemonset
Daemonset manifest
2020-10-12 16:53:51 +01:00
thebsdbox
e69e7a3519 Remove dead code. 2020-10-12 16:52:54 +01:00
thebsdbox
79509d961f Daemonset manifest
This adds the capability to generate a deamonset manifest
2020-10-08 12:53:19 +01:00
Daniel Finneran
d82fd174b4 Merge pull request #74 from plunder-app/0.1.8
0.1.8 merge
2020-09-09 12:13:49 +01:00
Daniel Finneran
9fd4ea33b3 Merge pull request #73 from thebsdbox/leaderElectionFlags
LeaderElection configuration
2020-09-09 10:38:51 +01:00
thebsdbox
32c06956d4 Adds defaults
This setting adds the Kubernetes controller defaults (which we can now overide)
2020-09-09 10:38:29 +01:00
thebsdbox
507fab9d6b LeaderElection configuration
This commit adds customisation of the LeaderElection
2020-09-03 11:46:23 +01:00
Daniel Finneran
8b4ba5efaf Merge pull request #70 from thebsdbox/leaderElectionFork
Leader election fork
2020-09-03 11:27:12 +01:00
Daniel Finneran
d7c5314828 Merge pull request #68 from thebsdbox/multiple_peers
Add multiple peers
2020-08-28 16:38:49 +01:00
thebsdbox
d8505dab55 This is a complete hack
This does the following:
 - Bumps client-go a version
 - Adds the missing `contexts`
 - Takes leaderElection from Kubernetes upstream and adds a fix
2020-08-28 16:36:24 +01:00
thebsdbox
4c0fc591fe Add multiple peers
This will add all peers found in the api to the BGP configuration
2020-08-27 13:00:20 +01:00
Plunder
67eff74597 Merge pull request #67 from thebsdbox/bgp
This adds BGP functionality to kube-vip
2020-08-26 14:44:45 +01:00
Plunder
bf1b265e62 Merge branch '0.1.8' into bgp 2020-08-26 14:44:04 +01:00
Plunder
f26cc8ef49 Merge pull request #55 from thebsdbox/dhcp
This adds the beginnings of DHCP capability
2020-08-26 14:42:35 +01:00
Plunder
814ab87a91 Merge branch '0.1.8' into dhcp 2020-08-26 14:41:56 +01:00
thebsdbox
0580c70003 fixes to makefile version 2020-08-26 14:40:38 +01:00
thebsdbox
4d5b834994 Fixes to error detection on a packet host 2020-08-26 14:35:33 +01:00
thebsdbox
b1935293ba Improves the failover speed by 400%
Originally the failover would stop/start BGP server instance, which involve peering and other steps. The BGP server is started during `kube-vip` startup and address advertisement happens when needed.  Also a fix to an environment variable so that the CIDR value was passed correctly.
2020-08-25 14:27:07 +01:00
thebsdbox
ea11c6fbbd This fixes numerous issues
- Adds the CIDR to the VIP, needed for BGP
- Seperates the EIP association to a seperate function making leader Election code clearer
- Fixes to environment variable names
- Clean un-needed `fatalf` errors
- Added additional comments
2020-08-25 10:07:54 +01:00
thebsdbox
b6e3434ee3 This adds BGP functionality to kube-vip
Details to be added.
2020-08-24 19:27:42 +01:00
thebsdbox
543f72405d The service is now updated
Once DHCP has given a lease we can now update the service with the correct IP address
2020-07-09 18:01:54 +01:00
thebsdbox
3a63437f4e This adds the beginnings of DHCP capability
If a user passes the static loadBalancer address `0.0.0.0` then `kube-vip` will attempt to use DHCP.

- TODO: update service
2020-07-09 17:22:24 +01:00
184 changed files with 22712 additions and 3564 deletions

4
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
# Enable GitHub funding
github: [kube-vip]

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS/Distro: [e.g. Ubuntu 1804]
- Kubernetes Version: [e.g. v.1.18]
- Kube-vip Version: [e.g. 0.2.3]
**`Kube-vip.yaml`:**
If Possible add in your kube-vip manifest (please remove anything that is confidential)
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

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

@@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
- package-ecosystem: docker
directory: /
schedule:
interval: weekly

31
.github/workflows/anchore-syft.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow checks out code, builds an image, performs a container image
# scan with Anchore's Syft tool, and uploads the results to the GitHub Dependency
# submission API.
# For more information on the Anchore sbom-action usage
# and parameters, see https://github.com/anchore/sbom-action. For more
# information about the Anchore SBOM tool, Syft, see
# https://github.com/anchore/syft
name: Anchore Syft SBOM scan
on:
release:
types: [published]
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.ref_name }}
- name: Anchore SBOM Action
uses: anchore/sbom-action@v0.20.4
with:
format: cyclonedx-json

51
.github/workflows/ci-pull-request.yaml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: For each PR
on:
pull_request:
jobs:
e2e-tests:
runs-on: ubuntu-latest
name: E2E tests
strategy:
matrix:
mode: ["arp", "rt", "bgp"]
fail-fast: true
max-parallel: 1
steps:
- name: Ensure fs wont cause issues
run: sudo sysctl fs.inotify.max_user_instances=8192 && sudo sysctl fs.inotify.max_user_watches=524288
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build image locally
run: make dockerx86Local
- name: Run Manifest generation tests
run: make manifest-test
- name: Run ARP mode tests v1.29.0 onwards
run: make e2e-tests129-arp
if: matrix.mode== 'arp'
- name: Run RT mode tests v1.29.0 onwards
run: make e2e-tests129-rt
if: matrix.mode== 'rt'
- name: Get GoBGP binaries
run: make get-gobgp
if: matrix.mode== 'bgp'
- name: Run BGP mode tests v1.29.0 onwards
run: sudo -E PATH=$PATH DOCKER_API_VERSION=1.48 make e2e-tests129-bgp
if: matrix.mode== 'bgp'
service-e2e-tests:
runs-on: ubuntu-latest
name: E2E service tests
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build image with iptables
run: make dockerx86ActionIPTables
- name: Run tests
run: DOCKERTAG=action make service-tests

62
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: For each commit
on:
push:
pull_request:
jobs:
validation:
runs-on: ubuntu-latest
name: Checks and linters
steps:
- name: Init
run: sudo apt-get update && sudo apt-get install -y build-essential && sudo sysctl fs.inotify.max_user_instances=8192 && sudo sysctl fs.inotify.max_user_watches=524288
- name: Install golangci-lint
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.8
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: All checks
run: make check
unit-tests:
runs-on: ubuntu-latest
name: Unit tests
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Run tests
run: make unit-tests
integration-tests:
name: Integration tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Run tests
run: make integration-tests
image-vul-check:
runs-on: ubuntu-latest
name: Image vulnerability scan
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build image with iptables
run: make dockerx86ActionIPTables
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: "plndr/kube-vip:action"
format: "table"
exit-code: "1"
ignore-unfixed: true
vuln-type: "os,library"
severity: "CRITICAL,HIGH"

75
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '17 10 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

52
.github/workflows/main.yaml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Build and publish main image regularly
on:
schedule:
- cron: '25 0 * * *'
workflow_dispatch:
jobs:
nightly_build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to Github Packages
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build standard version
id: docker_build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
push: ${{ github.event_name != 'pull_request' }}
tags: >-
plndr/kube-vip:${{ github.ref_name }},
ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}
- name: Build iptables version
id: docker_build_iptables
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile_iptables
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
push: ${{ github.event_name != 'pull_request' }}
tags: >-
plndr/kube-vip-iptables:${{ github.ref_name }},
ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }}
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

64
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: Publish Releases to Docker Hub and GitHub Container Registry
on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to Github Packages
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate Metadata
uses: docker/metadata-action@v5.7.0
id: metadata
with:
labels: |
org.opencontainers.image.documentation=https://kube-vip.io/docs/
- name: Build and push main branch
id: docker_build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.metadata.outputs.labels }}
tags: >-
plndr/kube-vip:${{ github.ref_name }},
plndr/kube-vip:latest,
ghcr.io/kube-vip/kube-vip:${{ github.ref_name }},
ghcr.io/kube-vip/kube-vip:latest
- name: Build iptables version and push main branch
id: docker_build_iptables
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile_iptables
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.metadata.outputs.labels }}
tags: >-
plndr/kube-vip-iptables:${{ github.ref_name }},
plndr/kube-vip-iptables:latest,
ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }},
ghcr.io/kube-vip/kube-vip-iptables:latest
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
.idea
kube-vip
.vscode
bin
testing/e2e/etcd/certs
pkg/etcd/etcd.pid
pkg/etcd/etcd-data

13
.golangci.yml Normal file
View File

@@ -0,0 +1,13 @@
run:
timeout: 10m
linters:
enable:
- bodyclose
- gofmt
- goimports
- revive
- gosec
- misspell
- unconvert
- unparam

10
CODEOWNERS Normal file
View File

@@ -0,0 +1,10 @@
# For more information on the syntax of the CODEOWNERS file, see:
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
# The Kube-Vip maintainers team
* @thebsdbox @yastij
# Emeritus Maintainers
#
# N/A

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
conduct@kube-vip.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

289
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,289 @@
# Developer Guide
Thank you for taking the time out to contribute to the **kube-vip** project!
This guide will walk you through the process of making your first commit and how
to effectively get it merged upstream.
<!-- toc -->
- [Getting Started](#getting-started)
- [Contribute](#contribute)
- [GitHub Workflow](#github-workflow)
- [Getting reviewers](#getting-reviewers)
- [Inclusive Naming](#inclusive-naming)
- [Building and testing your change](#building-and-testing-your-change)
- [Reverting a commit](#reverting-a-commit)
- [Sign-off Your Work](#sign-off-your-work)
- [Issue and PR Management](#issue-and-pr-management)
- [Filing An Issue](#filing-an-issue)
- [Issue Triage](#issue-triage)
<!-- /toc -->
## Getting Started
To get started, let's ensure you have completed the following prerequisites for
contributing to project **kube-vip**:
1. Read and observe the [code of conduct](CODE_OF_CONDUCT.md).
2. Check out the [Architecture documentation](https://kube-vip.io) for the **kube-vip**
architecture and design.
3. Set up your [development environment](docs/contributors/manual-installation.md)
Now that you're setup, skip ahead to learn how to [contribute](#contribute).
**Also**, A GitHub account will be required in order to submit code changes and
interact with the project. For committing any changes in **Github** it is required for
you to have a [github account](https://github.com/join).
## Contribute
There are multiple ways in which you can contribute, either by contributing
code in the form of new features or bug-fixes or non-code contributions like
helping with code reviews, triaging of bugs, documentation updates, filing
[new issues](#filing-an-issue) or writing blogs/manuals etc.
### GitHub Workflow
Developers work in their own forked copy of the repository and when ready,
submit pull requests to have their changes considered and merged into the
project's repository.
1. Fork your own copy of the repository to your GitHub account by clicking on
`Fork` button on [kube-vip's GitHub repository](https://github.com/kube-vip/kube-vip).
2. Clone the forked repository on your local setup.
```bash
git clone https://github.com/$user/kube-vip
```
Add a remote upstream to track upstream kube-vip repository.
```bash
git remote add upstream https://github.com/kube-vip/kube-vip
```
Never push to upstream remote
```bash
git remote set-url --push upstream no_push
```
3. Create a topic branch.
```bash
git checkout -b branchName
```
4. Make changes and commit it locally. Make sure that your commit is
[signed](#sign-off-your-work).
```bash
git add <modifiedFile>
git commit -s
```
5. Update the "Unreleased" section of the [CHANGELOG](CHANGELOG.md) for any
significant change that impacts users.
6. Keeping branch in sync with upstream.
```bash
git checkout branchName
git fetch upstream
git rebase upstream/main
```
7. Push local branch to your forked repository.
```bash
git push -f $remoteBranchName branchName
```
8. Create a Pull request on GitHub.
Visit your fork at `https://github.com/kube-vip/kube-vip` and click
`Compare & Pull Request` button next to your `remoteBranchName` branch.
### Getting reviewers
Once you have opened a Pull Request (PR), reviewers will be assigned to your
PR and they may provide review comments which you need to address.
Commit changes made in response to review comments to the same branch on your
fork. Once a PR is ready to merge, squash any *fix review feedback, typo*
and *merged* sorts of commits.
To make it easier for reviewers to review your PR, consider the following:
1. Follow the golang [coding conventions](https://github.com/golang/go/wiki/CodeReviewComments).
2. Format your code with `make golangci-fix`; if the [linters](ci/README.md) flag an issue that
cannot be fixed automatically, an error message will be displayed so you can address the issue.
3. Follow [git commit](https://chris.beams.io/posts/git-commit/) guidelines.
4. Follow [logging](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md) guidelines.
If your PR fixes a bug or implements a new feature, add the appropriate test
cases to our [automated test suite](ci/README.md) to guarantee enough
coverage. A PR that makes significant code changes without contributing new test
cases will be flagged by reviewers and will not be accepted.
### Inclusive Naming
For symbol names and documentation, do not introduce new usage of harmful
language such as 'master / slave' (or 'slave' independent of 'master') and
'blacklist / whitelist'. For more information about what constitutes harmful
language and for a reference word replacement list, please refer to the
[Inclusive Naming Initiative](https://inclusivenaming.org/).
We are committed to removing all harmful language from the project. If you
detect existing usage of harmful language in code or documentation, please
report the issue to us or open a Pull Request to address it directly. Thanks!
### Building and testing your change
To build the **kube-vip** Docker image together with all **kube-vip** bits, you can simply
do:
1. Checkout your feature branch and `cd` into it.
2. Run `make dockerx86`
The second step will compile the **kube-vip** code in a `golang` container, and build
a `Ubuntu 20.04` Docker image that includes all the generated binaries. [`Docker`](https://docs.docker.com/install)
must be installed on your local machine in advance.
Alternatively, you can build the **kube-vip** code in your local Go environment. The
**kube-vip** project uses the [Go modules support](https://github.com/golang/go/wiki/Modules) which was introduced in Go 1.11. It
facilitates dependency tracking and no longer requires projects to live inside
the `$GOPATH`.
To develop locally, you can follow these steps:
1. [Install Go 1.19](https://golang.org/doc/install)
2. Checkout your feature branch and `cd` into it.
3. To build all Go files and install them under `bin`, run `make bin`
4. To run all Go unit tests, run `make test-unit`
5. To build the **kube-vip** Ubuntu Docker image separately with the binaries generated in step 2, run `make ubuntu`
### CI testing
For more information about the tests we run as part of CI, please refer to
[ci/README.md](ci/README.md).
### Reverting a commit
1. Create a branch in your forked repo
```bash
git checkout -b revertName
```
2. Sync the branch with upstream
```bash
git fetch upstream
git rebase upstream/main
```
3. Create a revert based on the SHA of the commit. The commit needs to be
[signed](#sign-off-your-work).
```bash
git revert -s SHA
```
4. Push this new commit.
```bash
git push $remoteRevertName revertName
```
5. Create a Pull Request on GitHub.
Visit your fork at `https://github.com/kube-vip/kube-vip` and click
`Compare & Pull Request` button next to your `remoteRevertName` branch.
### Sign-off Your Work
It is recommended to sign your work when contributing to the **kube-vip**
repository.
Git provides the `-s` command-line option to append the required line
automatically to the commit message:
```bash
git commit -s -m 'This is my commit message'
```
For an existing commit, you can also use this option with `--amend`:
```bash
git commit -s --amend
```
If more than one person works on something it's possible for more than one
person to sign-off on it. For example:
```bash
Signed-off-by: Some Developer somedev@example.com
Signed-off-by: Another Developer anotherdev@example.com
```
We use the [DCO Github App](https://github.com/apps/dco) to enforce that all
commits in a Pull Request include the required `Signed-off-by` line. If this is
not the case, the app will report a failed status for the Pull Request and it
will be blocked from being merged.
Compared to our earlier CLA, DCO tends to make the experience simpler for new
contributors. If you are contributing as an employee, there is no need for your
employer to sign anything; the DCO assumes you are authorized to submit
contributions (it's your responsibility to check with your employer).
## Issue and PR Management
We use labels and workflows (some manual, some automated with GitHub Actions) to
help us manage triage, prioritize, and track issue progress. For a detailed
discussion, see [docs/issue-management.md](docs/contributors/issue-management.md).
### Filing An Issue
Help is always appreciated. If you find something that needs fixing, please file
an issue [here](https://github.com/kube-vip/kube-vip/issues). Please ensure
that the issue is self explanatory and has enough information for an assignee to
get started.
Before picking up a task, go through the existing
[issues](https://github.com/kube-vip/kube-vip/issues) and make sure that your
change is not already being worked on. If it does not exist, please create a new
issue and discuss it with other members.
For simple contributions to **kube-vip**, please ensure that this minimum set of
labels are included on your issue:
* **kind** -- common ones are `kind/feature`, `kind/support`, `kind/bug`,
`kind/documentation`, or `kind/design`. For an overview of the different types
of issues that can be submitted, see [Issue and PR
Kinds](#issue-and-pr-kinds).
The kind of issue will determine the issue workflow.
* **area** (optional) -- if you know the area the issue belongs in, you can assign it.
Otherwise, another community member will label the issue during triage. The
area label will identify the area of interest an issue or PR belongs in and
will ensure the appropriate reviewers shepherd the issue or PR through to its
closure. For an overview of areas, see the
[`docs/github-labels.md`](docs/contributors/github-labels.md).
* **size** (optional) -- if you have an idea of the size (lines of code, complexity,
effort) of the issue, you can label it using a [size label](#size). The size
can be updated during backlog grooming by contributors. This estimate is used
to guide the number of features selected for a milestone.
All other labels will be assigned during issue triage.
### Issue Triage
Once an issue has been submitted, the CI (GitHub actions) or a human will
automatically review the submitted issue or PR to ensure that it has all relevant
information. If information is lacking or there is another problem with the
submitted issue, an appropriate `triage/<?>` label will be applied.
After an issue has been triaged, the maintainers can prioritize the issue with
an appropriate `priority/<?>` label.
Once an issue has been submitted, categorized, triaged, and prioritized it
is marked as `ready-to-work`. A ready-to-work issue should have labels
indicating assigned areas, prioritization, and should not have any remaining
triage labels.

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:experimental
FROM golang:1.13-alpine as dev
FROM golang:1.24.5-alpine3.22 as dev
RUN apk add --no-cache git ca-certificates make
RUN adduser -D appuser
COPY . /src/
@@ -12,5 +12,8 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \
CGO_ENABLED=0 GOOS=linux make build
FROM scratch
# Add Certificates into the image, for anything that does API calls
COPY --from=dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
# Add kube-vip binary
COPY --from=dev /src/kube-vip /
ENTRYPOINT ["/kube-vip"]
ENTRYPOINT ["/kube-vip"]

21
Dockerfile_iptables Normal file
View File

@@ -0,0 +1,21 @@
# syntax=docker/dockerfile:experimental
FROM golang:1.24.5-alpine3.22 as dev
RUN apk add --no-cache git make
RUN adduser -D appuser
COPY . /src/
WORKDIR /src
ENV GO111MODULE=on
RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \
--mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux make build
FROM alpine:3.22.1
# Update pkgs and add iptables
RUN apk upgrade && \
apk add --no-cache iptables iptables-legacy
# Add kube-vip binary
COPY --from=dev /src/kube-vip /
ENTRYPOINT ["/kube-vip"]

141
Makefile
View File

@@ -1,12 +1,12 @@
SHELL := /bin/sh
# The name of the executable (default is current directory name)
TARGET := kube-vip
.DEFAULT_GOAL: $(TARGET)
.DEFAULT_GOAL := $(TARGET)
# These will be provided to the target
VERSION := 0.1.7
VERSION := v1.0.0
BUILD := `git rev-parse HEAD`
# Operating System Default (LINUX)
@@ -14,18 +14,14 @@ TARGETOS=linux
# Use linker flags to provide version/build settings to the target
LDFLAGS=-ldflags "-s -w -X=main.Version=$(VERSION) -X=main.Build=$(BUILD) -extldflags -static"
# go source files, ignore vendor directory
SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*")
DOCKERTAG ?= $(VERSION)
REPOSITORY = plndr
REPOSITORY ?= plndr
.PHONY: all build clean install uninstall fmt simplify check run
.PHONY: all build clean install uninstall simplify check run e2e-tests
all: check install
$(TARGET): $(SRC)
$(TARGET):
@go build $(LDFLAGS) -o $(TARGET)
build: $(TARGET)
@@ -41,44 +37,143 @@ install:
uninstall: clean
@rm -f $$(which ${TARGET})
fmt:
@gofmt -l -w $(SRC)
demo:
@cd demo
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New Multi Architecture Docker image created
@cd ..
## Remote (push of images)
# This build a local docker image (x86 only) for quick testing
dockerx86Dev:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):dev .
@echo New single x86 Architecture Docker image created
dockerx86Iptables:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables --push -t $(REPOSITORY)/$(TARGET):dev .
@echo New single x86 Architecture Docker image created
dockerx86IptablesLocal:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New single x86 Architecture Docker image created
dockerx86:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New Multi Architecture Docker image created
@echo New single x86 Architecture Docker image created
docker:
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@-rm ./kube-vip
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New Multi Architecture Docker image created
## Local (docker load of images)
# This will build a local docker image (x86 only), use make dockerLocal for all architectures
dockerx86Local:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New Multi Architecture Docker image created
dockerx86Action:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):action .
@echo New Multi Architecture Docker image created
dockerx86ActionIPTables:
@-rm ./kube-vip
@docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables --load -t $(REPOSITORY)/$(TARGET):action .
@echo New Multi Architecture Docker image created
dockerLocal:
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@-rm ./kube-vip
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New Multi Architecture Docker image created
simplify:
@gofmt -s -l -w $(SRC)
@gofmt -s -l -w *.go pkg cmd
check:
@test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'"
@for d in $$(go list ./... | grep -v /vendor/); do golint $${d}; done
@go tool vet ${SRC}
go mod tidy
test -z "$(git status --porcelain)"
test -z $(shell gofmt -l *.go pkg cmd) || echo "[WARN] Fix formatting issues with 'make simplify'"
golangci-lint run
go vet ./...
run: install
@$(TARGET)
manifests:
@make build
@mkdir -p ./docs/manifests/$(VERSION)/
@./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services > ./docs/manifests/$(VERSION)/kube-vip-arp.yaml
@./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --enableLoadBalancer > ./docs/manifests/$(VERSION)/kube-vip-arp-lb.yaml
@./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --bgp --controlplane --services > ./docs/manifests/$(VERSION)/kube-vip-bgp.yaml
@./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --inCluster > ./docs/manifests/$(VERSION)/kube-vip-arp-ds.yaml
@./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --inCluster --enableLoadBalancer > ./docs/manifests/$(VERSION)/kube-vip-arp-ds-lb.yaml
@./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster > ./docs/manifests/$(VERSION)/kube-vip-bgp-ds.yaml
@./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster > ./docs/manifests/$(VERSION)/kube-vip-bgp-em-ds.yaml
@-rm ./kube-vip
manifest-test:
docker run $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest pod --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services
docker run $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest pod --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --enableLoadBalancer
docker run $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest pod --interface eth0 --vip 192.168.0.1 --bgp --controlplane --services
docker run $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest daemonset --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --inCluster
docker run $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest daemonset --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --inCluster --enableLoadBalancer
docker run $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster
unit-tests:
go test ./...
integration-tests:
go test -tags=integration,e2e -v ./pkg/etcd
e2e-tests:
GOMAXPROCS=4 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd
e2e-tests129-arp:
GOMAXPROCS=4 TEST_MODE=arp V129=true K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e
e2e-tests129-rt:
GOMAXPROCS=4 TEST_MODE=rt V129=true K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e
e2e-tests129-bgp:
GOMAXPROCS=4 TEST_MODE=bgp V129=true K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e
e2e-tests129: e2e-tests129-arp e2e-tests129-rt e2e-tests129-bgp
service-tests:
E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/services -Services -simple -deployments -leaderActive -leaderFailover -localDeploy -egress -egressIPv6 -dualStack
trivy: dockerx86ActionIPTables
docker run -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.47.0 \
image \
--format table \
--exit-code 1 \
--ignore-unfixed \
--vuln-type 'os,library' \
--severity 'CRITICAL,HIGH' \
$(REPOSITORY)/$(TARGET):action
kind-quick:
echo "Standing up your cluster"
kind create cluster --config ./testing/kind/kind.yaml --name kube-vip
kubectl apply -f https://kube-vip.io/manifests/rbac.yaml
kubectl create configmap --namespace kube-system kubevip --from-literal range-global=172.18.100.10-172.18.100.30
kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml
kind load docker-image --name kube-vip $(REPOSITORY)/$(TARGET):$(DOCKERTAG)
docker run --network host --rm $(REPOSITORY)/$(TARGET):$(DOCKERTAG) manifest daemonset --services --inCluster --arp --servicesElection --interface eth0 | kubectl apply -f -
kind-reload:
kind load docker-image $(REPOSITORY)/$(TARGET):$(DOCKERTAG) --name kube-vip
kubectl rollout restart -n kube-system daemonset/kube-vip-ds
get-gobgp:
mkdir -p bin
wget -nc --directory-prefix=bin https://github.com/osrg/gobgp/releases/download/v3.37.0/gobgp_3.37.0_linux_amd64.tar.gz
tar -xvzf bin/gobgp_3.37.0_linux_amd64.tar.gz -C bin

View File

@@ -1,25 +1,39 @@
# kube-vip
High Availability and Load-Balancing
**NOTE** All documentation of both usage and architecture are now available at [https://kube-vip.io](https://kube-vip.io)
![](https://github.com/kube-vip/kube-vip/raw/main/kube-vip.png)
[![Build and publish main image regularly](https://github.com/kube-vip/kube-vip/actions/workflows/main.yaml/badge.svg)](https://github.com/kube-vip/kube-vip/actions/workflows/main.yaml) [![LFX Health Score](https://img.shields.io/static/v1?label=Health%20Score&message=Healthy&color=A7F3D0&logo=linuxfoundation&logoColor=white&style=flat)](https://insights.linuxfoundation.org/project/kube-vip) [![LFX Active Contributors](https://img.shields.io/static/v1?label=Active%20contributors%20(1Y)&message=212&color=0094FF&logo=linuxfoundation&logoColor=white&style=flat)](https://insights.linuxfoundation.org/project/kube-vip)
## Overview
Kubernetes Virtual IP and Load-Balancer for both control pane and Kubernetes services
Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services
The idea behind `kube-vip` is a small self-contained Highly-Available option for all environments, especially:
- Bare-Metal
- Edge (arm / Raspberry PI)
- Virtualisation
- Pretty much anywhere else :)
![](/overview.png)
**NOTE:** All documentation of both usage and architecture are now available at [https://kube-vip.io](https://kube-vip.io).
The `kube-vip` application builds a multi-node or multi-pod cluster to provide High-Availability. When a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster.
## Features
When running **out of cluster** it will use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) clustering technology
Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer).
When running **in cluster** it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection)
- VIP addresses can be both IPv4 or IPv6
- Control Plane with ARP (Layer 2) or BGP (Layer 3)
- Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science))
- Control Plane HA with kubeadm (static Pods)
- Control Plane HA with K3s/and others (daemonsets)
- Service LoadBalancer using [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) for ARP (Layer 2)
- Service LoadBalancer using multiple nodes with BGP
- Service LoadBalancer address pools per namespace or global
- Service LoadBalancer address via (existing network DHCP)
- Service LoadBalancer address exposure to gateway via UPNP
- Egress! Kube-vip will utilise a service loadbalancer as both the ingress and **egress** for a pod.
- ... manifest generation, vendor API integrations and many more...
## Why?
@@ -31,53 +45,27 @@ The purpose of `kube-vip` is to simplify the building of HA Kubernetes clusters,
**VIP**:
- [Keepalived](https://www.keepalived.org/)
- [Ucarp](https://ucarp.wordpress.com/)
- [UCARP](https://ucarp.wordpress.com/)
- Hardware Load-balancer (functionality differs per vendor)
**LoadBalancing**:
- [HAProxy](http://www.haproxy.org/)
- [Nginx](http://nginx.com)
- Hardware Load-balancer(functionality differs per vendor)
- Hardware Load-balancer (functionality differs per vendor)
All of these would require a separate level of configuration and in some infrastructures multiple teams in order to implement. Also when considering the software components, they may require packaging into containers or if theyre pre-packaged then security and transparency may be an issue. Finally, in edge environments we may have limited room for hardware (no HW load-balancer) or packages solutions in the correct architectures might not exist (e.g. ARM). Luckily with `kube-vip` being written in GO, its small(ish) and easy to build for multiple architectures, with the added security benefit of being the only thing needed in the container.
## Troubleshooting and Feedback
## Standalone Usage
Please raise issues on the GitHub repository and as mentioned check the documentation at [https://kube-vip.io](https://kube-vip.io/).
The usage of `kube-vip` can either be directly by taking the binary / building yourself (`make build`), or alternatively through a pre-built docker container which can be found in the plunder Docker Hub repository [https://hub.docker.com/r/plndr/kube-vip](https://hub.docker.com/r/plndr/kube-vip). For further
## Contributing
### Configuration
Thanks for taking the time to join our community and start contributing! We welcome pull requests. Feel free to dig through the [issues](https://github.com/kube-vip/kube-vip/issues) and jump in.
To generate the basic `yaml` configuration:
:warning: This project has issue compiling on MacOS, please compile it on linux distribution
```
kube-vip sample config > config.yaml
```
## Star History
Modify the `localPeer` section to match this particular instance (local IP address/port etc..) and ensure that the `remotePeers` section is correct for the current instance and all other instances in the cluster. Also ensure that the `interface` is the correct interface that the `vip` will bind to.
## Starting a simple cluster
To start `kube-vip` ensure the configuration for the `localPeers` and `remotePeers` is correct for each instance and the cluster as a whole and start:
```
kube-vip start -c /config.yaml
INFO[0000] Reading configuration from [config.yaml]
INFO[0000] 2020-02-01T15:41:04.287Z [INFO] raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:server1 Address:192.168.0.70:10000} {Suffrage:Voter ID:server2 Address:192.168.0.71:10000} {Suffrage:Voter ID:server3 Address:192.168.0.72:10000}]"
INFO[0000] 2020-02-01T15:41:04.287Z [INFO] raft: entering follower state: follower="Node at 192.168.0.70:10000 [Follower]" leader=
INFO[0000] Started
INFO[0000] The Node [] is leading
INFO[0001] The Node [] is leading
INFO[0001] 2020-02-01T15:41:05.522Z [WARN] raft: heartbeat timeout reached, starting election: last-leader=
INFO[0001] 2020-02-01T15:41:05.522Z [INFO] raft: entering candidate state: node="Node at 192.168.0.70:10000 [Candidate]" term=2
INFO[0001] 2020-02-01T15:41:05.522Z [DEBUG] raft: votes: needed=2
INFO[0001] 2020-02-01T15:41:05.522Z [DEBUG] raft: vote granted: from=server1 term=2 tally=1
INFO[0001] 2020-02-01T15:41:05.523Z [DEBUG] raft: newer term discovered, fallback to follower
INFO[0001] 2020-02-01T15:41:05.523Z [INFO] raft: entering follower state: follower="Node at 192.168.0.70:10000 [Follower]" leader=
INFO[0001] 2020-02-01T15:41:05.838Z [WARN] raft: failed to get previous log: previous-index=2 last-index=1 error="log not found"
INFO[0002] The Node [192.168.0.72:10000] is leading
```
After a few seconds with additional nodes started a leader election will take place and the leader will assume the **vip**.
[![Star History Chart](https://api.star-history.com/svg?repos=kube-vip/kube-vip&type=Date)](https://star-history.com/#kube-vip/kube-vip&Date)

35
ROADMAP.md Normal file
View File

@@ -0,0 +1,35 @@
# Kube-Vip Roadmap
This document outlines the roadmap for the **kube-vip** project and only covers the technologies within this particular project, other projects that augment or provide additional functionality (such as cloud-providers) may have their own roadmaps in future. The functionality for **kube-vip** has grown either been developed organically or through real-world needs, and this is the first attempt to put into words a plan for the future of **kube-vip** and will additional evolve over time. This means that items listed or detailed here are not necessarily set in stone and the roadmap can grow/shrink as the project matures. We definitely welcome suggestions and ideas from everyone about the roadmap and **kube-vip** features. Reach us through Issues, Slack or email <catch-all>@kube-vip.io.
## Release methodology
The **kube-vip** project attempts to follow a tick-tock release cycle, this typically means that one release will come **packed** with new features where the following release will come with fixes, code sanitation and performance enhancements.
## Roadmap
The **kube-vip** project offers two main areas of functionality:
- HA Kubernetes clusters through a control-plane VIP
- Kubernetes `service type:LoadBalancer`
Whilst both of these functions share underlying technologies and code they will have slightly differing roadmaps.
### HA Kubernetes Control Plane
- **Re-implement LoadBalancing** - due to a previous request the HTTP loadbalancing was removed leaving just HA for the control plane. This functionality will be re-implemented either through the original round-robin HTTP requests or utilising IPVS.
- **Utilise the Kubernetes API to determine additional Control Plane members** - Once a single node cluster is running **kube-vip** could use the API to determine the additional members, at this time a Cluster-API provider needs to drop a static manifest per CP node.
- **Re-evaluate raft** - **kube-vip** is mainly designed to run within a Kubernetes cluster, however it's original design was a raft cluster external to Kubernetes. Unfortunately given some of the upgrade paths identified in things like CAPV moving to leaderElection within Kubernetes became a better idea.
## Kubernetes `service type:LoadBalancer`
- **`ARP` LeaderElection per loadBalancer** - Currently only one pod that is elected leader will field all traffic for a VIP.. extending this to generate a leaderElection token per service would allow services to proliferate across all pods across the cluster
- **Aligning of `service` and `manager`** - The move to allow hybrid (be both HA control plane and offer load-balancer services at the same time) introduced a duplicate code path.. these need to converge as it's currently confusing for contributors.
## Global **Kube-Vip** items
- **Improved metrics** - At this time the scaffolding for monitoring exists, however this needs drastically extending to provide greater observability to what is happening within **kube-vip**
- **Windows support** - The Go SDK didn't support the capability for low-levels sockets for ARP originally, this should be revisited.
- **Additional BGP features** :
- Communities
- BFD

View File

@@ -1,146 +0,0 @@
package cmd
import (
"fmt"
"github.com/ghodss/yaml"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
appv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// [sample configuration] - flags
var cliConfig kubevip.Config
var cliConfigLB kubevip.LoadBalancer
var cliLocalPeer string
var cliRemotePeers, cliBackends []string
func init() {
kubeVipSampleConfig.Flags().StringVar(&cliConfig.Interface, "interface", "eth0", "Name of the interface to bind to")
kubeVipSampleConfig.Flags().StringVar(&cliConfig.VIP, "vip", "192.168.0.1", "The Virtual IP address")
kubeVipSampleConfig.Flags().BoolVar(&cliConfig.SingleNode, "singleNode", false, "Start this instance as a single node")
kubeVipSampleConfig.Flags().BoolVar(&cliConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader")
kubeVipSampleConfig.Flags().BoolVar(&cliConfig.GratuitousARP, "arp", true, "Use ARP broadcasts to improve VIP re-allocations")
kubeVipSampleConfig.Flags().StringVar(&cliLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port")
kubeVipSampleConfig.Flags().StringSliceVar(&cliRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma seperated remotePeers, format: id:address:port")
// Load Balancer flags
kubeVipSampleConfig.Flags().BoolVar(&cliConfigLB.BindToVip, "lbBindToVip", false, "Bind example load balancer to VIP")
kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)")
kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance")
kubeVipSampleConfig.Flags().IntVar(&cliConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on")
kubeVipSampleConfig.Flags().StringSliceVar(&cliBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma seperated backends, format: address:port")
}
var kubeVipSampleConfig = &cobra.Command{
Use: "config",
Short: "Generate a Sample configuration",
Run: func(cmd *cobra.Command, args []string) {
// // Parse localPeer
// p, err := kubevip.ParsePeerConfig(cliLocalPeer)
// if err != nil {
// cmd.Help()
// log.Fatalln(err)
// }
// cliConfig.LocalPeer = *p
// // Parse remotePeers
// //Iterate backends
// for i := range cliRemotePeers {
// p, err := kubevip.ParsePeerConfig(cliRemotePeers[i])
// if err != nil {
// cmd.Help()
// log.Fatalln(err)
// }
// cliConfig.RemotePeers = append(cliConfig.RemotePeers, *p)
// }
// //Iterate backends
// for i := range cliBackends {
// b, err := kubevip.ParseBackendConfig(cliBackends[i])
// if err != nil {
// cmd.Help()
// log.Fatalln(err)
// }
// cliConfigLB.Backends = append(cliConfigLB.Backends, *b)
// }
// Add the basic Load-Balancer to the configuration
cliConfig.LoadBalancers = append(cliConfig.LoadBalancers, cliConfigLB)
err := cliConfig.ParseFlags(cliLocalPeer, cliRemotePeers, cliBackends)
if err != nil {
cmd.Help()
log.Fatalln(err)
}
err = kubevip.ParseEnvironment(&cliConfig)
if err != nil {
cmd.Help()
log.Fatalln(err)
}
cliConfig.PrintConfig()
},
}
var kubeVipSampleManifest = &cobra.Command{
Use: "manifest",
Short: "Generate a Sample kubernetes manifest",
Run: func(cmd *cobra.Command, args []string) {
// Generate the sample manifest specification
p := &appv1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "kube-vip",
Namespace: "kube-system",
},
Spec: appv1.PodSpec{
Containers: []appv1.Container{
{
Name: "kube-vip",
Image: fmt.Sprintf("docker.io/plndr/kube-vip:%s", Release.Version),
SecurityContext: &appv1.SecurityContext{
Capabilities: &appv1.Capabilities{
Add: []appv1.Capability{
"NET_ADMIN",
"SYS_TIME",
},
},
},
Args: []string{
"start",
"-c",
"/etc/kube-vip/config.yaml",
},
VolumeMounts: []appv1.VolumeMount{
{
Name: "config",
MountPath: "/etc/kube-vip/",
},
},
},
},
Volumes: []appv1.Volume{
{
Name: "config",
VolumeSource: appv1.VolumeSource{
HostPath: &appv1.HostPathVolumeSource{
Path: "/etc/kube-vip/",
},
},
},
},
HostNetwork: true,
},
}
b, _ := yaml.Marshal(p)
fmt.Printf(string(b))
},
}

View File

@@ -2,54 +2,18 @@ package cmd
import (
"fmt"
"net"
"os"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// kubeadm adds two subcommands for managing a vip during a kubeadm init/join
// It is designed to operate "light" and take minimal input to start
var initConfig kubevip.Config
var initLoadBalancer kubevip.LoadBalancer
// Points to a kubernetes configuration file
var kubeConfigPath string
func init() {
localpeer, err := autoGenLocalPeer()
if err != nil {
log.Fatalln(err)
}
initConfig.LocalPeer = *localpeer
//initConfig.Peers = append(initConfig.Peers, *localpeer)
kubeKubeadm.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to")
kubeKubeadm.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address")
kubeKubeadm.PersistentFlags().BoolVar(&initConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader")
kubeKubeadm.PersistentFlags().BoolVar(&initConfig.AddPeersAsBackends, "addPeersToLB", true, "The Virtual IP address")
kubeKubeadm.PersistentFlags().BoolVar(&initConfig.GratuitousARP, "arp", true, "Enable Arp for Vip changes")
kubeKubeadm.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering")
kubeKubeadm.PersistentFlags().BoolVar(&initConfig.EnablePacket, "packet", false, "This will use the Packet API (requires the token ENV) to update the EIP <-> VIP")
kubeKubeadm.PersistentFlags().StringVar(&initConfig.PacketAPIKey, "packetKey", "", "The API token for authenticating with the Packet API")
kubeKubeadm.PersistentFlags().StringVar(&initConfig.PacketProject, "packetProject", "", "The name of project already created within Packet")
// Load Balancer flags
kubeKubeadm.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "lbEnable", false, "Enable a load-balancer on the VIP")
kubeKubeadm.PersistentFlags().BoolVar(&initLoadBalancer.BindToVip, "lbBindToVip", true, "Bind example load balancer to VIP")
kubeKubeadm.PersistentFlags().StringVar(&initLoadBalancer.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)")
kubeKubeadm.PersistentFlags().StringVar(&initLoadBalancer.Name, "lbName", "Kubeadm Load Balancer", "The name of a load balancer instance")
kubeKubeadm.PersistentFlags().IntVar(&initLoadBalancer.Port, "lbPort", 6443, "Port that load balancer will expose on")
kubeKubeadm.PersistentFlags().IntVar(&initLoadBalancer.BackendPort, "lbBackEndPort", 6444, "A port that all backends may be using (optional)")
kubeKubeadmJoin.Flags().StringVar(&kubeConfigPath, "config", "/etc/kubernetes/admin.conf", "The path of a Kubernetes configuration file")
kubeKubeadm.AddCommand(kubeKubeadmInit)
@@ -59,8 +23,8 @@ func init() {
var kubeKubeadm = &cobra.Command{
Use: "kubeadm",
Short: "Kubeadm functions",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
_ = cmd.Help()
// TODO - A load of text detailing what's actually happening
},
}
@@ -69,124 +33,84 @@ var kubeKubeadmInit = &cobra.Command{
Use: "init",
Short: "kube-vip init",
Long: "The \"init\" subcommand will generate the Kubernetes manifest that will be started by kubeadm through the kubeadm init process",
Run: func(cmd *cobra.Command, args []string) {
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
kubevip.ParseEnvironment(&initConfig)
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Error("parsing environment", "err", err)
return
}
// TODO - check for certain things VIP/interfaces
if initConfig.Interface == "" {
cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")
_ = cmd.Help()
log.Error("No interface is specified for kube-vip to bind to")
return
}
if initConfig.VIP == "" {
cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
if initConfig.VIP == "" && initConfig.Address == "" {
_ = cmd.Help()
log.Error("No address is specified for kube-vip to expose services on")
return
}
cfg := kubevip.GenerateManifestFromConfig(&initConfig, Release.Version)
fmt.Println(cfg)
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Error("generating VIPSubnet", "err", err)
return
}
}
cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster)
fmt.Println(cfg) // output manifest to stdout
},
}
var kubeKubeadmJoin = &cobra.Command{
Use: "join",
Short: "kube-vip join",
Run: func(cmd *cobra.Command, args []string) {
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
kubevip.ParseEnvironment(&initConfig)
// TODO - check for certain things VIP/interfaces
if initConfig.Interface == "" {
cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Error("parsing environment", "err", err)
return
}
if initConfig.VIP == "" {
cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
// TODO - check for certain things VIP/interfaces
if initConfig.Interface == "" {
_ = cmd.Help()
log.Error("No interface is specified for kube-vip to bind to")
return
}
if initConfig.VIP == "" && initConfig.Address == "" {
_ = cmd.Help()
log.Error("No address is specified for kube-vip to expose services on")
return
}
if _, err := os.Stat(kubeConfigPath); os.IsNotExist(err) {
log.Fatalf("Unable to find file [%s]", kubeConfigPath)
log.Error("kubeConfig not found", "Path", kubeConfigPath)
return
}
// We will use kubeconfig in order to find all the master nodes
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)
if err != nil {
log.Fatal(err.Error())
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err.Error())
}
opts := metav1.ListOptions{}
opts.LabelSelector = "node-role.kubernetes.io/master"
nodes, err := clientset.CoreV1().Nodes().List(opts)
// Iterate over all nodes that are masters and find the details to build a peer list
for x := range nodes.Items {
// Get hostname and address
var nodeAddress, nodeHostname string
for y := range nodes.Items[x].Status.Addresses {
switch nodes.Items[x].Status.Addresses[y].Type {
case corev1.NodeHostName:
nodeHostname = nodes.Items[x].Status.Addresses[y].Address
case corev1.NodeInternalIP:
nodeAddress = nodes.Items[x].Status.Addresses[y].Address
}
}
newPeer, err := kubevip.ParsePeerConfig(fmt.Sprintf("%s:%s:%d", nodeHostname, nodeAddress, 10000))
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
panic(err.Error())
log.Error("generating VIPSubnet", "err", err)
return
}
initConfig.RemotePeers = append(initConfig.RemotePeers, *newPeer)
}
// Generate manifest and print
cfg := kubevip.GenerateManifestFromConfig(&initConfig, Release.Version)
fmt.Println(cfg)
cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster)
fmt.Println(cfg) // output manifest to stdout
},
}
func autoGenLocalPeer() (*kubevip.RaftPeer, error) {
// hostname // address // defaultport
h, err := os.Hostname()
if err != nil {
return nil, err
}
var a string
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
for _, address := range addrs {
// check the address type and if it is not a loopback the display it
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
a = ipnet.IP.String()
break
}
}
}
if a == "" {
return nil, fmt.Errorf("Unable to find local address")
}
return &kubevip.RaftPeer{
ID: h,
Address: a,
Port: 10000,
}, nil
}

150
cmd/kube-vip-manifests.go Normal file
View File

@@ -0,0 +1,150 @@
package cmd
import (
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/spf13/cobra"
)
// manifests will eventually deprecate the kubeadm set of subcommands
// manifests will be used to generate:
// - Pod spec manifest, mainly used for a static pod (kubeadm)
// - Daemonset manifest, mainly used to run kube-vip as a deamonset within Kubernetes (k3s/rke)
// - RBAC manifest, used to generate the RBAC permissions for kube-vip
var taint, role, rolebinding bool
func init() {
kubeManifest.PersistentFlags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes")
kubeManifestDaemon.PersistentFlags().BoolVar(&taint, "taint", false, "Taint the manifest for only running on control planes")
kubeManifestRbac.PersistentFlags().BoolVar(&role, "role", false, "Generate only a Role inside the serviceNamespace access")
kubeManifestRbac.PersistentFlags().BoolVar(&rolebinding, "rolebinding", false, "Generate only a RoleBinding for namespaced access")
kubeManifest.AddCommand(kubeManifestPod)
kubeManifest.AddCommand(kubeManifestDaemon)
kubeManifest.AddCommand(kubeManifestRbac)
}
var kubeManifest = &cobra.Command{
Use: "manifest",
Short: "Manifest functions",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
_ = cmd.Help()
// TODO - A load of text detailing what's actually happening
},
}
var kubeManifestPod = &cobra.Command{
Use: "pod",
Short: "Generate a Pod Manifest",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
var err error
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
if err := kubevip.ParseEnvironment(&initConfig); err != nil {
log.Error("parsing environment", "err", err)
return
}
// The control plane has a requirement for a VIP being specified
if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) {
_ = cmd.Help()
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Error("config parse", "err", err)
return
}
}
cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster)
fmt.Println(cfg) // output manifest to stdout
},
}
var kubeManifestDaemon = &cobra.Command{
Use: "daemonset",
Short: "Generate a Daemonset Manifest",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
var err error
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
if err := kubevip.ParseEnvironment(&initConfig); err != nil {
log.Error("parsing environment", "err", err)
return
}
// The control plane has a requirement for a VIP being specified
if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) {
_ = cmd.Help()
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Error("config parse", "err", err)
return
}
}
cfg := kubevip.GenerateDaemonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint)
fmt.Println(cfg) // output manifest to stdout
},
}
var kubeManifestRbac = &cobra.Command{
Use: "rbac",
Short: "Generate an RBAC Manifest",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
var err error
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
if err := kubevip.ParseEnvironment(&initConfig); err != nil {
log.Error("parsing environment", "err", err)
return
}
// The control plane has a requirement for a VIP being specified
if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) {
_ = cmd.Help()
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Error("generating VIPSubnet", "err", err)
return
}
}
saCfg := kubevip.GenerateSA(&initConfig)
roleCfg := kubevip.GenerateRole(&initConfig, role)
if role {
rolebinding = true
}
roleBindingCfg := kubevip.GenerateRoleBinding(rolebinding, saCfg, roleCfg)
// Output the YAML manifests to stdout
fmt.Println("---") // Separator for YAML documents
fmt.Println(kubevip.TransformApplyObjectToManifest(saCfg))
fmt.Println("---") // Separator for YAML documents
fmt.Println(kubevip.TransformApplyObjectToManifest(roleCfg))
fmt.Println("---") // Separator for YAML documents
fmt.Println(kubevip.TransformApplyObjectToManifest(roleBindingCfg))
},
}

View File

@@ -1,122 +0,0 @@
package cmd
import (
"os"
"os/signal"
"github.com/plunder-app/kube-vip/pkg/cluster"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// Start as a single node (no cluster), start as a leader in the cluster
var startConfig kubevip.Config
var startConfigLB kubevip.LoadBalancer
var startLocalPeer, startKubeConfigPath string
var startRemotePeers, startBackends []string
var inCluster bool
func init() {
// Get the configuration file
kubeVipStart.Flags().StringVarP(&configPath, "config", "c", "", "Path to a kube-vip configuration")
kubeVipStart.Flags().BoolVarP(&disableVIP, "disableVIP", "d", false, "Disable the VIP functionality")
// Pointers so we can see if they're nil (and not called)
kubeVipStart.Flags().StringVar(&startConfig.Interface, "interface", "eth0", "Name of the interface to bind to")
kubeVipStart.Flags().StringVar(&startConfig.VIP, "vip", "192.168.0.1", "The Virtual IP address")
kubeVipStart.Flags().BoolVar(&startConfig.SingleNode, "singleNode", false, "Start this instance as a single node")
kubeVipStart.Flags().BoolVar(&startConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader")
kubeVipStart.Flags().BoolVar(&startConfig.GratuitousARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations")
kubeVipStart.Flags().StringVar(&startLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port")
kubeVipStart.Flags().StringSliceVar(&startRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma seperated remotePeers, format: id:address:port")
// Load Balancer flags
kubeVipStart.Flags().BoolVar(&startConfigLB.BindToVip, "lbBindToVip", false, "Bind example load balancer to VIP")
kubeVipStart.Flags().StringVar(&startConfigLB.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)")
kubeVipStart.Flags().StringVar(&startConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance")
kubeVipStart.Flags().IntVar(&startConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on")
kubeVipStart.Flags().IntVar(&startConfigLB.BackendPort, "lbBackEndPort", 6443, "A port that all backends may be using (optional)")
kubeVipStart.Flags().StringSliceVar(&startBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma seperated backends, format: address:port")
// Cluster configuration
kubeVipStart.Flags().StringVar(&startKubeConfigPath, "kubeConfig", "/etc/kubernetes/admin.conf", "The path of a kubernetes configuration file")
kubeVipStart.Flags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes")
kubeVipStart.Flags().BoolVar(&startConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering")
}
var kubeVipStart = &cobra.Command{
Use: "start",
Short: "Start the Virtual IP / Load balancer",
Run: func(cmd *cobra.Command, args []string) {
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
var err error
// If a configuration file is loaded, then it will overwrite flags
if configPath != "" {
c, err := kubevip.OpenConfig(configPath)
if err != nil {
log.Fatalf("%v", err)
}
startConfig = *c
}
// parse environment variables, these will overwrite anything loaded or flags
err = kubevip.ParseEnvironment(&startConfig)
if err != nil {
log.Fatalln(err)
}
var newCluster *cluster.Cluster
if startConfig.SingleNode {
// If the Virtual IP isn't disabled then create the netlink configuration
newCluster, err = cluster.InitCluster(&startConfig, disableVIP)
if err != nil {
log.Fatalf("%v", err)
}
// Start a single node cluster
newCluster.StartSingleNode(&startConfig, disableVIP)
} else {
if disableVIP {
log.Fatalln("Cluster mode requires the Virtual IP to be enabled, use single node with no VIP")
}
// If the Virtual IP isn't disabled then create the netlink configuration
newCluster, err = cluster.InitCluster(&startConfig, disableVIP)
if err != nil {
log.Fatalf("%v", err)
}
if startConfig.EnableLeaderElection {
cm, err := cluster.NewManager(startKubeConfigPath, inCluster)
if err != nil {
log.Fatalf("%v", err)
}
// Leader Cluster will block
err = newCluster.StartLeaderCluster(&startConfig, cm)
if err != nil {
log.Fatalf("%v", err)
}
} else {
// // Start a multi-node (raft) cluster, this doesn't block so will wait on signal
err = newCluster.StartRaftCluster(&startConfig)
if err != nil {
log.Fatalf("%v", err)
}
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
<-signalChan
newCluster.Stop()
}
}
},
}

View File

@@ -1,29 +1,35 @@
package cmd
import (
"context"
"fmt"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/plunder-app/kube-vip/pkg/service"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/cobra"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/manager"
"github.com/kube-vip/kube-vip/pkg/vip"
)
// Path to the configuration file
var configPath string
// Disable the Virtual IP (bind to the existing network stack)
var disableVIP bool
// Run as a load balancer service (within a pod / kubernetes)
var serviceArp bool
// Is kube-vip running within cluster
var inCluster bool
// ConfigMap name within a Kubernetes cluster
var configMap string
// Configure the level of loggin
var logLevel uint32
// Points to a kubernetes configuration file
var kubeConfigPath string
// Release - this struct contains the release information populated when building kube-vip
var Release struct {
@@ -31,32 +37,122 @@ var Release struct {
Build string
}
// Structs used via the various subcommands
var (
initConfig kubevip.Config
initLoadBalancer kubevip.LoadBalancer
)
var kubeVipCmd = &cobra.Command{
Use: "kube-vip",
Short: "This is a server for providing a Virtual IP and load-balancer for the Kubernetes control-plane",
}
func init() {
// Basic flags
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPSubnet, "vipSubnet", "", "The Virtual IP address subnet e.g. /32 /24 /8 etc.. (Default to 32 for IPv4 and 128 for IPv6)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.NodeName, "nodeName", "", "Name to be used for lease holder. Must be unique for each node/instance")
// VIP flags
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP")
kubeVipCmd.PersistentFlags().Uint16Var(&initConfig.Port, "port", 6443, "Port for the VIP")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for VIP changes")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableWireguard, "wireguard", false, "Enable Wireguard for services VIPs")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableRoutingTable, "table", false, "Enable Routing Table for services VIPs")
// LoadBalancer flags
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "enableLoadBalancer", false, "enable loadbalancing on the VIP with IPVS")
kubeVipCmd.PersistentFlags().Uint16Var(&initConfig.LoadBalancerPort, "lbPort", 6443, "loadbalancer port for the VIP")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerForwardingMethod, "lbForwardingMethod", "local", "loadbalancer forwarding method")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.MirrorDestInterface, "mirrorDestInterface", "", "network interface where all traffic that traverses the service interface will be mirrored to. Source interface will use default interface is servicesInterface is not set.")
// Clustering type (leaderElection)
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.LeaderElectionType, "leaderElectionType", "kubernetes", "Defines the backend to run the leader election: kubernetes or etcd. Defaults to kubernetes.")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.LeaseName, "leaseName", "plndr-cp-lock", "Name of the lease that is used for leader election")
kubeVipCmd.PersistentFlags().IntVar(&initConfig.LeaseDuration, "leaseDuration", 5, "Length of time (in seconds) a Kubernetes leader lease can be held for")
kubeVipCmd.PersistentFlags().IntVar(&initConfig.RenewDeadline, "leaseRenewDuration", 3, "Length of time (in seconds) a Kubernetes leader can attempt to renew its lease")
kubeVipCmd.PersistentFlags().IntVar(&initConfig.RetryPeriod, "leaseRetry", 1, "Length of time (in seconds) the LeaderElector clients should wait between tries of actions")
// BGP flags
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableBGP, "bgp", false, "This will enable BGP support within kube-vip")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIF, "sourceIF", "", "The source interface for bgp peering (not to be used with sourceIP)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIP, "sourceIP", "", "The source address for bgp peering (not to be used with sourceIF)")
kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPConfig.AS, "localAS", 65000, "The local AS number for the bgp server")
kubeVipCmd.PersistentFlags().Uint64Var(&initConfig.BGPConfig.HoldTime, "bgpHoldTimer", 30, "The hold timer for all bgp peers (it defines the time a session is held)")
kubeVipCmd.PersistentFlags().Uint64Var(&initConfig.BGPConfig.KeepaliveInterval, "bgpKeepAliveInterval", 10, "The keepalive interval for all bgp peers (it defines the heartbeat of keepalive messages)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer")
kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPPeerConfig.MultiHop, "multihop", false, "This will enable BGP multihop support")
kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{}, "Comma separated BGP Peer, format: address:as:password:multihop")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPConfig.Zebra.Enabled, "zebra", false, "This will enable Zebra support within kube-vip")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.Zebra.URL, "zebraUrl", "unix:/var/run/frr/zserv.api", "Path to the unix domain socket for connecting to Zebra daemon")
kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPConfig.Zebra.Version, "zebraVersion", 6, "Zebra API Version")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.Zebra.SoftwareName, "zebraSoftwareName", "frr8.3", "Software Name for Zebra")
// Namespace for kube-vip
kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The namespace for the configmap defined within the cluster")
// Manage logging
kubeVipCmd.PersistentFlags().Uint32Var(&logLevel, "log", 4, "Set the level of logging")
kubeVipCmd.PersistentFlags().Int32Var(&initConfig.Logging, "log", 0, "Set the level of logging")
// Service flags
kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "kube-vip", "The configuration map defined within the cluster")
kubeVipService.Flags().StringVarP(&service.Interface, "interface", "i", "eth0", "Name of the interface to bind to")
kubeVipService.Flags().BoolVar(&service.OutSideCluster, "OutSideCluster", false, "Start Controller outside of cluster")
kubeVipService.Flags().BoolVar(&service.EnableArp, "arp", false, "Use ARP broadcasts to improve VIP re-allocations")
kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster")
// Routing Table flags
kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingTableID, "tableID", 198, "The routing table used for all table entries")
kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingTableType, "tableType", unix.RTN_UNICAST, "The type of route that will be added to the routing table")
kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingProtocol, "routingProtocol", 248, "The routing protocol value used to create routes")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.CleanRoutingTable, "cleanRoutingTable", false, "Clean routing table of redundant routes on start")
// Behaviour flags
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPlane, "controlplane", false, "Enable HA for control plane")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DetectControlPlane, "autodetectcp", false, "Determine working address for control plane (from loopback)")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services")
// Extended behaviour flags
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServicesElection, "servicesElection", false, "Enable leader election per kubernetes service")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoadBalancerClassOnly, "lbClassOnly", false, "Enable load balancing only for services with LoadBalancerClass \"kube-vip.io/kube-vip-class\"")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerClassName, "lbClassName", "kube-vip.io/kube-vip-class", "Name of load balancer class for kube-VIP, defaults to \"kube-vip.io/kube-vip-class\"")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoadBalancerClassLegacyHandling, "lbClassNameLegacyHandling", true, "Use legacy LoadBalancer class name handling (e.g. accepting services both with empty and non-empty class)")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=<VIP address>\", defaults to false")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesLeaseName, "servicesLeaseName", "plndr-svcs-lock", "Name of the lease that is used for leader election for services (in arp mode)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.DNSMode, "dnsMode", "first", "Name of the mode that DNS lookup will be performed (first, ipv4, ipv6, dual)")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DisableServiceUpdates, "disableServiceUpdates", false, "If true, kube-vip will process services as usual, but will not update service's Status.LoadBalancer.Ingress slice")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableEndpoints, "enableEndpoints", false, "If enabled, kube-vip will only advertise services, but will use the (deprecated since v1.33) endpoints for IP addresses")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoInterfaceGlobalScope, "loInterfaceGlobalScope", false, "If true, kube-vip will set global scope when using the lo interface, otherwise a host scope will be used by default")
kubeVipCmd.PersistentFlags().IntVar(&initConfig.HealthCheckPort, "healthCheckPort", 0, "If set to non-zero (> 1024), then this is the port that the healthcheck will listen on")
// Prometheus HTTP Server
kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server")
// Etcd
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.CAFile, "etcdCACert", "", "Verify certificates of TLS-enabled secure servers using this CA bundle file")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.ClientCertFile, "etcdCert", "", "Identify secure client using this TLS certificate file")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.ClientKeyFile, "etcdKey", "", "Identify secure client using this TLS key file")
kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.Etcd.Endpoints, "etcdEndpoints", nil, "Etcd member endpoints")
// Kubernetes client specific flags
kubeVipCmd.PersistentFlags().StringVar(&initConfig.K8sConfigFile, "k8sConfigPath", "/etc/kubernetes/admin.conf", "Path to the configuration file used with the Kubernetes client")
kubeVipCmd.AddCommand(kubeKubeadm)
kubeVipCmd.AddCommand(kubeManifest)
kubeVipCmd.AddCommand(kubeVipManager)
kubeVipCmd.AddCommand(kubeVipSample)
kubeVipCmd.AddCommand(kubeVipService)
kubeVipCmd.AddCommand(kubeVipStart)
kubeVipCmd.AddCommand(kubeVipVersion)
// Sample commands
kubeVipSample.AddCommand(kubeVipSampleConfig)
kubeVipSample.AddCommand(kubeVipSampleManifest)
// Set the logging level for all subsequent functions
log.SetLogLoggerLevel(log.Level(initConfig.Logging))
}
// Execute - starts the command parsing process
@@ -70,7 +166,7 @@ func Execute() {
var kubeVipVersion = &cobra.Command{
Use: "version",
Short: "Version and Release information about the Kubernetes Virtual IP Server",
Run: func(cmd *cobra.Command, args []string) {
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
fmt.Printf("Kube-VIP Release Information\n")
fmt.Printf("Version: %s\n", Release.Version)
fmt.Printf("Build: %s\n", Release.Build)
@@ -80,56 +176,298 @@ var kubeVipVersion = &cobra.Command{
var kubeVipSample = &cobra.Command{
Use: "sample",
Short: "Generate a Sample configuration",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
_ = cmd.Help()
},
}
var kubeVipService = &cobra.Command{
Use: "service",
Short: "Start the Virtual IP / Load balancer as a service within a Kubernetes cluster",
Run: func(cmd *cobra.Command, args []string) {
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
// User Environment variables as an option to make manifest clearer
envInterface := os.Getenv("vip_interface")
if envInterface != "" {
service.Interface = envInterface
// parse environment variables, these will overwrite anything loaded or flags
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Error("parsing env", "err", err)
return
}
// Change RTN_UNSPEC to default type
if initConfig.RoutingProtocol == unix.RTN_UNSPEC {
initConfig.RoutingProtocol = unix.RTN_UNICAST
}
// Set the logging level for all subsequent functions
log.SetLogLoggerLevel(log.Level(initConfig.Logging))
if err := initConfig.CheckInterface(); err != nil {
log.Error("checking interface", "err", err)
return
}
// User Environment variables as an option to make manifest clearer
envConfigMap := os.Getenv("vip_configmap")
if envInterface != "" {
if envConfigMap != "" {
configMap = envConfigMap
}
envLog := os.Getenv("vip_loglevel")
if envLog != "" {
logLevel, err := strconv.Atoi(envLog)
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
panic(fmt.Sprintf("Unable to parse environment variable [vip_loglevel], should be int"))
log.Error("generating CIDR", "err", err)
return
}
log.SetLevel(log.Level(logLevel))
}
envArp := os.Getenv("vip_arp")
if envArp != "" {
arpBool, err := strconv.ParseBool(envArp)
if err != nil {
panic(fmt.Sprintf("Unable to parse environment variable [arp], should be bool (true/false)"))
}
service.EnableArp = arpBool
}
// Define the new service manager
mgr, err := service.NewManager(configMap)
mgr, err := manager.New(configMap, &initConfig)
if err != nil {
log.Fatalf("%v", err)
log.Error("new manager", "err", err)
return
}
// Start the service manager, this will watch the config Map and construct kube-vip services for it
err = mgr.Start()
if err != nil {
log.Fatalf("%v", err)
log.Error("manager start", "err", err)
return
}
},
}
var kubeVipManager = &cobra.Command{
Use: "manager",
Short: "Start the kube-vip manager",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
// parse environment variables, these will overwrite anything loaded or flags
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Error("parsing environment", "err", err)
return
}
// Change RTN_UNSPEC to default type
if initConfig.RoutingProtocol == unix.RTN_UNSPEC {
initConfig.RoutingProtocol = unix.RTN_UNICAST
}
// Set the logging level for all subsequent functions
log.SetLogLoggerLevel(log.Level(initConfig.Logging))
// Ensure there is an address to generate the CIDR from
if initConfig.VIPSubnet == "" && initConfig.Address != "" {
initConfig.VIPSubnet, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Error("No interface is specified for kube-vip to bind to")
return
}
}
// Welome messages
log.Info("kube-vip.io", "version", Release.Version, "build", Release.Build)
// start prometheus server
if initConfig.PrometheusHTTPServer != "" {
go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{
Addr: initConfig.PrometheusHTTPServer,
})
}
// Determine the kube-vip mode
var mode string
if initConfig.EnableARP {
mode = "ARP"
}
if initConfig.EnableBGP {
mode = "BGP"
}
if initConfig.EnableWireguard {
mode = "Wireguard"
}
if initConfig.EnableRoutingTable {
mode = "Routing Table"
}
// Provide configuration to output/logging
log.Info("starting", "namespace", initConfig.Namespace, "Mode", mode, "Control Plane", initConfig.EnableControlPlane, "Services", initConfig.EnableServices)
// End if nothing is enabled
if !initConfig.EnableServices && !initConfig.EnableControlPlane {
log.Error("no features are enabled")
return
}
if !initConfig.EnableARP && strings.Contains(initConfig.VIPSubnet, kubevip.Auto) {
log.Error("auto subnet discovery cannot be used outside ARP mode")
return
}
if strings.Contains(initConfig.VIPSubnet, kubevip.Auto) && initConfig.Address != "" {
log.Error("auto subnet discovery cannot be used if VIP address was provided")
return
}
// If we're using wireguard then all traffic goes through the wg0 interface
if initConfig.EnableWireguard {
if initConfig.Interface == "" {
// Set the vip interface to the wireguard interface
initConfig.Interface = "wg0"
}
log.Info("configuring Wireguard networking")
l, err := netlink.LinkByName(initConfig.Interface)
if err != nil {
if strings.Contains(err.Error(), "Link not found") {
log.Warn("attempting to create wireguard interface", "interface not found", initConfig.Interface)
err = netlink.LinkAdd(&netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: initConfig.Interface}})
if err != nil {
log.Error("adding link", "err", err)
return
}
l, err = netlink.LinkByName(initConfig.Interface)
if err != nil {
log.Error("finding link", "err", err)
return
}
}
}
err = netlink.LinkSetUp(l)
if err != nil {
log.Error("setting link UP", "err", err)
return
}
} else { // if we're not using Wireguard then we'll need to use an actual interface
// Check if the interface needs auto-detecting
if initConfig.Interface == "" {
log.Info("No interface is specified for VIP in config, auto-detecting default Interface")
defaultIF, err := vip.GetDefaultGatewayInterface()
if err != nil {
_ = cmd.Help()
log.Error("detecting interface", "err", err)
return
}
initConfig.Interface = defaultIF.Name
log.Info("kube-vip bind", "interface", initConfig.Interface)
go func() {
if err := vip.MonitorDefaultInterface(context.TODO(), defaultIF); err != nil {
log.Error("interface monitor", "err", err)
return
}
}()
}
}
// Perform a check on the state of the interface
if err := initConfig.CheckInterface(); err != nil {
log.Error("checking interface", "err", err)
return
}
// User Environment variables as an option to make manifest clearer
envConfigMap := os.Getenv("vip_configmap")
if envConfigMap != "" {
configMap = envConfigMap
}
// Define the new service manager
mgr, err := manager.New(configMap, &initConfig)
if err != nil {
log.Error("new manager", "err", err)
return
}
prometheus.MustRegister(mgr.PrometheusCollector()...)
// Start the service manager, this will watch the config Map and construct kube-vip services for it
err = mgr.Start()
if err != nil {
log.Error("start manager", "err", err)
return
}
},
}
// PrometheusHTTPServerConfig defines the Prometheus server configuration.
type PrometheusHTTPServerConfig struct {
// Addr sets the http server address used to expose the metric endpoint
Addr string
}
func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerConfig) {
var err error
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { //nolint TODO
_, _ = w.Write([]byte(`<html>
<head><title>kube-vip</title></head>
<body>
<h1>kube-vip Metrics</h1>
<p><a href="` + "/metrics" + `">Metrics</a></p>
</body>
</html>`))
})
srv := &http.Server{
Addr: config.Addr,
Handler: mux,
ReadHeaderTimeout: 2 * time.Second,
}
go func() {
if err = srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Error("prometheus HTTP server", "err", err)
return
}
}()
log.Info("prometheus HTTP server started")
<-ctx.Done()
log.Info("prometheus HTTP server stopped")
ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer func() {
cancel()
}()
if err = srv.Shutdown(ctxShutDown); err != nil {
log.Error("shutting down prometheus HTTP server", "err", err)
return
}
if err == http.ErrServerClosed {
err = nil
}
}
func GenerateCidrRange(address string) (string, error) {
var cidrs []string
addresses := strings.Split(address, ",")
for _, a := range addresses {
ip := net.ParseIP(a)
if ip == nil {
ips, err := net.LookupIP(a)
if len(ips) == 0 || err != nil {
return "", fmt.Errorf("invalid IP address: %s from [%s], %v", a, address, err)
}
ip = ips[0]
}
if ip.To4() != nil {
cidrs = append(cidrs, "32")
} else {
cidrs = append(cidrs, "128")
}
}
return strings.Join(cidrs, ","), nil
}

46
demo/README.md Normal file
View File

@@ -0,0 +1,46 @@
# Demo client-server
This contains some example code to determine how long "failovers" are taking within kube-vip, the server component should live within the cluster and the client should be externally.
## Deploy the server
Simply apply the manifest to a working cluster that has kube-vip deployed:
```
kubectl apply -f ./demo/server/deploy.yaml
```
Retrieve the loadBalancer IP that is fronting the service:
```
kubectl get svc demo-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demo-service LoadBalancer 10.104.18.147 192.168.0.217 10002:32529/UDP 117m
```
## Connect the client
From elsewhere, clone the kube-vip repository and connect the client to the server endpoint (loadBalancer IP) with the following command:
```
go run ./demo/client/main.go -address=<vip>
```
You will only see output when the client has reconcilled the connection to a pod beneath the service, where it will print the timestamp to reconnection along with the time in milliseconds it took:
```
15:58:35.916952 3008
15:58:45.947506 2005
15:58:57.983151 3007
15:59:08.013450 2005
15:59:20.046491 3008
15:59:30.076341 2507
15:59:42.110747 3008
```
## Kill some pods to test
On a machine or control plane that has `kubectl` and has the credentials to speak to the cluster we will run a command to find the demo pod and kill it every 10 seconds:
`while true ; do kubectl delete pod $(kubectl get pods | grep -v NAME | grep vip| awk '{ print $1 }'); sleep 10; done`

71
demo/client/main.go Normal file
View File

@@ -0,0 +1,71 @@
package main
import (
"bufio"
"flag"
"fmt"
"net"
"time"
)
const udpdata = "a3ViZS12aXAK=kube-vip"
func main() {
address := flag.String("address", "127.0.0.1", "The address of the server")
port := flag.Int("port", 10002, "the port of the server")
interval := flag.Float64("interval", 1000, "Interval in milliseconds")
flag.Parse()
var errorTime time.Time
var errorOccurred bool
for {
p := make([]byte, 2048)
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", *address, *port))
if err != nil {
if !errorOccurred {
errorTime = time.Now()
errorOccurred = true
}
continue
}
err = conn.SetDeadline(time.Now().Add(time.Duration(*interval) * time.Millisecond))
if err != nil {
//fmt.Printf("Connectivity error [%v]", err)
if !errorOccurred {
errorTime = time.Now()
errorOccurred = true
}
if err = conn.Close(); err != nil {
fmt.Printf("Error closing connection [%v]", err)
}
continue
}
_, err = fmt.Fprint(conn, udpdata)
if err != nil {
fmt.Printf("Error writing data [%v]", err)
}
_, err = bufio.NewReader(conn).Read(p)
if err != nil {
//fmt.Printf("read error %v\n", err)
if !errorOccurred {
errorTime = time.Now()
errorOccurred = true
}
if err = conn.Close(); err != nil {
fmt.Printf("Error closing connection [%v]", err)
}
continue
}
time.Sleep(time.Duration(*interval) * time.Millisecond)
if errorOccurred {
finishTime := time.Since(errorTime)
//fmt.Printf("connectivity reconciled in %dms\n", finishTime.Milliseconds())
//t :=time.Now().Format("15:04:05.000000")
fmt.Printf("%s %d\n", time.Now().Format("15:04:05.000000"), finishTime.Milliseconds())
errorOccurred = false
}
}
}

View File

@@ -1,3 +0,0 @@
module github.com/plunder-app/kube-vip/demo
go 1.13

View File

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:experimental
FROM golang:1.13-alpine as dev
FROM golang:1.19-alpine as dev
RUN apk add --no-cache git ca-certificates
RUN adduser -D appuser
COPY main.go /src/
@@ -13,4 +13,4 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \
FROM scratch
COPY --from=dev /src/demo /
CMD ["/demo"]
CMD ["/demo"]

View File

@@ -45,7 +45,7 @@ fmt:
@gofmt -l -w $(SRC)
docker:
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) .
@echo New Multi Architecture Docker image created
simplify:

View File

@@ -6,7 +6,7 @@ metadata:
app: kube-vip-demo
name: kube-vip-demo
spec:
replicas: 3
replicas: 1
selector:
matchLabels:
app: kube-vip-demo
@@ -30,4 +30,25 @@ spec:
ports:
- containerPort: 10001
- containerPort: 10002
status: {}
status: {}
---
apiVersion: v1
kind: Service
metadata:
name: demo-service
namespace: default
labels:
app: demo-service
annotations:
kube-vip.io/egress: "true"
spec:
type: LoadBalancer
# "Local" preserves the client source IP and avoids a second hop for
# LoadBalancer and NodePort
externalTrafficPolicy: Local
ports:
- name: demo-udp
port: 10002
protocol: UDP
selector:
app: kube-vip-demo

3
demo/server/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/kube-vip/kube-vip/demo
go 1.13

View File

@@ -32,7 +32,7 @@ func main() {
}
}
if serverType == strings.ToLower("udp") {
if serverType == "udp" {
// Start the UDP echo server
ServerAddr, err := net.ResolveUDPAddr("udp", ":10002")

View File

@@ -28,7 +28,7 @@ spec:
- kube-vip-cluster
topologyKey: "kubernetes.io/hostname"
containers:
- image: plndr/kube-vip:0.1.2
- image: ghcr.io/kube-vip/kube-vip:0.3.7
imagePullPolicy: Always
name: kube-vip
command:

View File

@@ -58,7 +58,7 @@ spec:
- kube-vip-cluster
topologyKey: "kubernetes.io/hostname"
containers:
- image: plndr/kube-vip:0.1.3
- image: ghcr.io/kube-vip/kube-vip:0.3.7
imagePullPolicy: Always
name: kube-vip
command:

55
example/deploy/0.3.5.yaml Normal file
View File

@@ -0,0 +1,55 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
creationTimestamp: null
name: kube-vip-ds
namespace: kube-system
spec:
selector:
matchLabels:
name: kube-vip-ds
template:
metadata:
creationTimestamp: null
labels:
name: kube-vip-ds
spec:
containers:
- args:
- manager
env:
- name: vip_arp
value: "true"
- name: vip_interface
value: eth0
- name: port
value: "6443"
- name: vip_cidr
value: "32"
- name: svc_enable
value: "true"
- name: vip_startleader
value: "false"
- name: vip_addpeerstolb
value: "true"
- name: vip_localpeer
value: ip-172-20-40-207:172.20.40.207:10000
- name: vip_address
image: plndr/kube-vip:v0.3.5
imagePullPolicy: Always
name: kube-vip
resources: {}
securityContext:
capabilities:
add:
- NET_ADMIN
- NET_RAW
- SYS_TIME
hostNetwork: true
serviceAccountName: kube-vip
updateStrategy: {}
status:
currentNumberScheduled: 0
desiredNumberScheduled: 0
numberMisscheduled: 0
numberReady: 0

19
example/deployment.yaml Normal file
View File

@@ -0,0 +1,19 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: nginx-interface-ens192-service
annotations:
kube-vip.io/serviceInterface: ens192
spec:
selector:
app: nginx
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP

13
example/service.yaml Normal file
View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP

174
go.mod
View File

@@ -1,19 +1,165 @@
module github.com/plunder-app/kube-vip
module github.com/kube-vip/kube-vip
go 1.13
go 1.24.4
require (
github.com/davecgh/go-spew v1.1.1
github.com/ghodss/yaml v1.0.0
github.com/hashicorp/raft v1.1.2
github.com/imdario/mergo v0.3.8 // indirect
github.com/packethost/packngo v0.2.0
github.com/cloudflare/ipvs v0.11.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/docker/docker v28.3.3+incompatible
github.com/florianl/go-conntrack v0.4.0
github.com/google/go-cmp v0.7.0
github.com/google/nftables v0.3.0
github.com/gookit/slog v0.5.8
github.com/huin/goupnp v1.3.0
github.com/insomniacslk/dhcp v0.0.0-20241224095048-b56fa0d5f25d
github.com/jpillora/backoff v1.0.0
github.com/mdlayher/ndp v1.1.0
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.37.0
github.com/osrg/gobgp/v3 v3.37.0
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.6
github.com/vishvananda/netlink v1.1.0
k8s.io/api v0.17.3
k8s.io/apimachinery v0.17.3
k8s.io/client-go v0.17.3
k8s.io/utils v0.0.0-20200124190032-861946025e34 // indirect
github.com/prometheus/client_golang v1.22.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
github.com/vishvananda/netlink v1.3.1
go.etcd.io/etcd/api/v3 v3.6.1
go.etcd.io/etcd/client/pkg/v3 v3.6.1
go.etcd.io/etcd/client/v3 v3.6.1
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329
golang.org/x/sync v0.15.0
golang.org/x/sys v0.33.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
google.golang.org/grpc v1.73.0
google.golang.org/protobuf v1.36.6
k8s.io/api v0.33.3
k8s.io/apimachinery v0.33.3
k8s.io/client-go v0.33.3
k8s.io/klog/v2 v2.130.1
sigs.k8s.io/kind v0.29.0
sigs.k8s.io/yaml v1.4.0
)
require (
al.essio.dev/pkg/shellescape v1.5.1 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/eapache/channels v1.1.0 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gookit/goutil v0.6.18 // indirect
github.com/gookit/gsr v0.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/k-sone/critbitgo v1.4.0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
github.com/mdlayher/packet v1.1.2 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tj/go-spin v1.1.0 // indirect
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xlab/c-for-go v1.3.0 // indirect
github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.33.0 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
modernc.org/cc/v4 v4.24.4 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/opt v0.1.4 // indirect
modernc.org/sortutil v1.2.1 // indirect
modernc.org/strutil v1.2.1 // indirect
modernc.org/token v1.1.0 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
)

775
go.sum
View File

@@ -1,332 +1,509 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho=
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
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/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
github.com/cloudflare/ipvs v0.11.0 h1:niLcbqfv8+RSYk+yI+jhiCIHobEdEhO++mcwCX0Znsw=
github.com/cloudflare/ipvs v0.11.0/go.mod h1:XsbuKcQpqb3rpjYPtsFsM8BNZlgLw+Z0iC6RhocqDd8=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
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/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
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-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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/protobuf v0.0.0-20161109072736-4bd1920723d7/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.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k=
github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18=
github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/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.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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
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/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.1 h1:9PZfAcVEvez4yhLH2TBU64/h/z4xlFI80cWXRrxuKuM=
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg=
github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
github.com/gookit/gsr v0.1.0 h1:0gadWaYGU4phMs0bma38t+Do5OZowRMEVlHv31p0Zig=
github.com/gookit/gsr v0.1.0/go.mod h1:7wv4Y4WCnil8+DlDYHBjidzrEzfHhXEoFjEA0pPPWpI=
github.com/gookit/slog v0.5.8 h1:XZCeHLQvvOZWcSUDZcqxXITsL9+d1ESsKZoASBmK1lI=
github.com/gookit/slog v0.5.8/go.mod h1:s0ViFOY/IgUuT4MDPF0l9x5/npcciy8pL4xwWZadnoc=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/raft v1.1.2 h1:oxEL5DDeurYxLd3UbcY/hccgSPhLLpiBZ1YxtWEq59c=
github.com/hashicorp/raft v1.1.2/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/insomniacslk/dhcp v0.0.0-20241224095048-b56fa0d5f25d h1:VkCNWh6tuQLgDBc6KrUOz/L1mCUQGnR1Ujj8uTgpwwk=
github.com/insomniacslk/dhcp v0.0.0-20241224095048-b56fa0d5f25d/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo=
github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE=
github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
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/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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE=
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
github.com/mdlayher/ndp v1.1.0 h1:QylGKGVtH60sKZUE88+IW5ila1Z/M9/OXhWdsVKuscs=
github.com/mdlayher/ndp v1.1.0/go.mod h1:FmgESgemgjl38vuOIyAHWUUL6vQKA/pQNkvXdWsdQFM=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q=
github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ=
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=
github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=
github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=
github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g=
github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/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 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
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.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/packethost/packngo v0.2.0 h1:mSlzOof8PsOWCy78sBMt/PwMJTEjjQ/rRvMixu4Nm6c=
github.com/packethost/packngo v0.2.0/go.mod h1:RQHg5xR1F614BwJyepfMqrKN+32IH0i7yX+ey43rEeQ=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/osrg/gobgp/v3 v3.37.0 h1:+ObuOdvj7G7nxrT0fKFta+EAupdWf/q1WzbXydr8IOY=
github.com/osrg/gobgp/v3 v3.37.0/go.mod h1:kVHVFy1/fyZHJ8P32+ctvPeJogn9qKwa1YCeMRXXrP0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
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/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
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/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xlab/c-for-go v1.3.0 h1:WDc+/E59g1OcZ4dYB4K9V4Doh4NnVBMYxaZFhNi77Lg=
github.com/xlab/c-for-go v1.3.0/go.mod h1:0qVnGIfoNg7c5gABptM38Y7nnXgAMo5KYWVQPycu63Y=
github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 h1:Sw125DKxZhPUI4JLlWugkzsrlB50jR9v2khiD9FxuSo=
github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245/go.mod h1:C+diUUz7pxhNY6KAoLgrTYARGWnt82zWTylZlxT92vk=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.6.1 h1:yJ9WlDih9HT457QPuHt/TH/XtsdN2tubyxyQHSHPsEo=
go.etcd.io/etcd/api/v3 v3.6.1/go.mod h1:lnfuqoGsXMlZdTJlact3IB56o3bWp1DIlXPIGKRArto=
go.etcd.io/etcd/client/pkg/v3 v3.6.1 h1:CxDVv8ggphmamrXM4Of8aCC8QHzDM4tGcVr9p2BSoGk=
go.etcd.io/etcd/client/pkg/v3 v3.6.1/go.mod h1:aTkCp+6ixcVTZmrJGa7/Mc5nMNs59PEgBbq+HCmWyMc=
go.etcd.io/etcd/client/v3 v3.6.1 h1:KelkcizJGsskUXlsxjVrSmINvMMga0VWwFF0tSPGEP0=
go.etcd.io/etcd/client/v3 v3.6.1/go.mod h1:fCbPUdjWNLfx1A6ATo9syUmFVxqHH9bCnPLBZmnLmMY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588=
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
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-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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-20201010224723-4f7140c49acb/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-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
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-20201020160332-67f06af15bc9/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.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
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-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/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-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
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.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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
k8s.io/api v0.17.3 h1:XAm3PZp3wnEdzekNkcmj/9Y1zdmQYJ1I4GKSBBZ8aG0=
k8s.io/api v0.17.3/go.mod h1:YZ0OTkuw7ipbe305fMpIdf3GLXZKRigjtZaV5gzC2J0=
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/apimachinery v0.17.3 h1:f+uZV6rm4/tHE7xXgLyToprg6xWairaClGVkm2t8omg=
k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg=
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
k8s.io/client-go v0.17.3 h1:deUna1Ksx05XeESH6XGCyONNFfiQmDdqeqUvicvP6nU=
k8s.io/client-go v0.17.3/go.mod h1:cLXlTMtWHkuK4tD360KpWz2gG2KtdWEr/OT02i3emRQ=
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20200124190032-861946025e34 h1:HjlUD6M0K3P8nRXmr2B9o4F9dUy9TCj/aEpReeyi6+k=
k8s.io/utils v0.0.0-20200124190032-861946025e34/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
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.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/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8=
k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE=
k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA=
k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA=
k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccorpus2 v1.5.2 h1:Ui+4tc58mf/W+2arcYCJR903y3zl3ecsI7Fpaaqozyw=
modernc.org/ccorpus2 v1.5.2/go.mod h1:Wifvo4Q/qS/h1aRoC2TffcHsnxwTikmi1AuLANuucJQ=
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kind v0.29.0 h1:3TpCsyh908IkXXpcSnsMjWdwdWjIl7o9IMZImZCWFnI=
sigs.k8s.io/kind v0.29.0/go.mod h1:ldWQisw2NYyM6k64o/tkZng/1qQW7OlzcN5a8geJX3o=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

BIN
kube-vip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -1,147 +0,0 @@
# Load Balancing a Kubernetes Cluster (Control-Plane)
This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster
`tl;dr version`
- Generate/modify first node `kube-vip` config/manifest
- `init` first node
- `join` remaining nodes
- Add remaining config/manifests
## Infrastructure architecture
The infrastructure for our example HA Kubernetes cluster is as follows:
| Node | Address |
|----------------|------------|
| VIP | 10.0.0.75 |
| controlPlane01 | 10.0.0.70 |
| controlPlane02 | 10.0.0.71 |
| controlPlane03 | 10.0.0.72 |
All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0.
### Generate the `kube-vip` configuration
Make sure that the config directory exists: `sudo mkdir -p /etc/kube-vip/`, this directory can be any directory however the `hostPath` in the manifest will need modifying to point to the correct path.
```
sudo docker run -it --rm plndr/kube-vip:0.1.5 sample config | sudo tee /etc/kube-vip/config.yaml
```
### Modify the configuration
**Cluster Configuration**
Modify the `remotePeers` to point to the correct addresses of the other two nodes, ensure that their `id` is unique otherwise this will confuse the raft algorithm. The `localPeer` should be the configuration of the current node (`controlPlane01`), which is where this instance of the cluster will run.
As this node will be the first node, it will need to elect itself leader as until this occurs the VIP wont be activated!
`startAsLeader: true`
**VIP Config**
We will need to set our VIP address to `192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `gratuitousARP: true`
**Load Balancer**
We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`.
We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict.
**config.yaml**
`user@controlPlane01:/etc/kube-vip$ cat config.yaml`
...
```
remotePeers:
- id: server2
address: 192.168.0.71
port: 10000
- id: server3
address: 192.168.0.72
port: 10000
localPeer:
id: server1
address: 192.168.0.70
port: 10000
vip: 192.168.0.75
gratuitousARP: true
singleNode: false
startAsLeader: true
interface: ens192
loadBalancers:
- name: Kubernetes Control Plane
type: tcp
port: 6443
bindToVip: true
backends:
- port: 6444
address: 192.168.0.70
- port: 6444
address: 192.168.0.71
- port: 6444
address: 192.168.0.72
```
### First Node
To generate the basic Kubernetes static pod `yaml` configuration:
Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/`
```
sudo docker run -it --rm plndr/kube-vip:0.1.5 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml
```
Ensure that `image: plndr/kube-vip:<x>` is modified to point to a specific version (`0.1.5` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. Also ensure that the `hostPath` points to the correct `kube-vip` configuration, if it isnt the above path.
The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server.
`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”`
Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod:
```
$ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
<...>
kube-system kube-vip-controlplane01 1/1 Running 0 10m
```
### Remaining Nodes
We first will need to create the `kube-vip` configuration that resides in `/etc/kube-vip/config.yaml` or we can regenerate it from scratch using the above example. Ensure that the configuration is almost identical with the `localPeer` and `remotePeers` sections are updated for each node. Finally, ensure that the remaining nodes will behave as standard cluster nodes by setting `startAsLeader: false`.
At this point **DONT** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour.
```
kubeadm join 192.168.0.75:6443 --token <tkn> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane --certificate-key <key>
```
**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesnt interfere with `kubeadm`).
```
sudo docker run -it --rm plndr/kube-vip:0.1.5 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml
```
Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected:
```
user@controlPlane01:~$ kubectl get pods -A | grep vip
kube-system kube-vip-controlplane01 1/1 Running 1 16m
kube-system kube-vip-controlplane02 1/1 Running 0 18m
kube-system kube-vip-controlplane03 1/1 Running 0 20m
```
If we look at the logs, we can see that the VIP is running on the second node and were waiting for our third node to join the cluster:
```
$ kubectl logs kube-vip-controlplane02 -n kube-system
time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading”
time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading”
```

View File

@@ -1,6 +1,8 @@
package main
import "github.com/plunder-app/kube-vip/cmd"
import (
"github.com/kube-vip/kube-vip/cmd"
)
// Version is populated from the Makefile and is tied to the release TAG
var Version string
@@ -9,6 +11,7 @@ var Version string
var Build string
func main() {
cmd.Release.Version = Version
cmd.Release.Build = Build
cmd.Execute()

149
pkg/arp/arp.go Normal file
View File

@@ -0,0 +1,149 @@
package arp
import (
"context"
log "log/slog"
"sync"
"time"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/vip"
)
type Manager struct {
instances map[string]*Instance
config *kubevip.Config
}
type Instance struct {
network vip.Network
ndp *vip.NdpResponder
mu sync.Mutex
counter int
}
func NewManager(config *kubevip.Config) *Manager {
return &Manager{
instances: make(map[string]*Instance),
config: config,
}
}
func NewInstance(network vip.Network, ndp *vip.NdpResponder) *Instance {
return &Instance{
ndp: ndp,
network: network,
counter: 1,
}
}
func (i *Instance) Name() string {
return i.network.ARPName()
}
func (m *Manager) Insert(instance *Instance) {
i, ok := m.instances[instance.Name()]
if !ok {
log.Info("inserting ARP/NDP instance", "name", instance.Name())
m.instances[instance.Name()] = instance
} else {
i.mu.Lock()
defer i.mu.Unlock()
i.counter++
}
}
func (m *Manager) Remove(instance *Instance) {
if i, ok := m.instances[instance.Name()]; ok {
i.mu.Lock()
defer i.mu.Unlock()
if i.counter > 1 {
i.counter--
} else {
log.Info("removing ARP/NDP instance", "name", instance.Name())
delete(m.instances, instance.Name())
}
}
}
func (m *Manager) Count(name string) int {
if i, ok := m.instances[name]; ok {
i.mu.Lock()
defer i.mu.Unlock()
return i.counter
}
return 0
}
func (m *Manager) StartAdvertisement(ctx context.Context) {
log.Info("Starting ARP/NDP advertisement")
for {
select {
case <-ctx.Done(): // if cancel() execute
return
default:
for _, instance := range m.instances {
if instance.counter > 0 {
ensureIPAndSendGratuitous(instance)
}
}
}
if m.config.ArpBroadcastRate < 500 {
log.Error("arp broadcast rate is too low", "rate (ms)", m.config.ArpBroadcastRate, "setting to (ms)", "3000")
m.config.ArpBroadcastRate = 3000
}
time.Sleep(time.Duration(m.config.ArpBroadcastRate) * time.Millisecond)
}
}
// ensureIPAndSendGratuitous - adds IP to the interface if missing, and send
// either a gratuitous ARP or gratuitous NDP. Re-adds the interface if it is IPv6
// and in a dadfailed state.
func ensureIPAndSendGratuitous(instance *Instance) {
iface := instance.network.Interface()
ipString := instance.network.IP()
// Check if IP is dadfailed
if instance.network.IsDADFAIL() {
log.Warn("IP address is in dadfailed state, removing config", "ip", ipString, "interface", iface)
deleted, err := instance.network.DeleteIP()
if err != nil {
log.Warn(err.Error())
}
if deleted {
log.Info("deleted and recreating address", "IP", ipString, "interface", iface)
// if _, err := instance.network.AddIP(false); err != nil {
// log.Error("failed to recreate address", "IP", ipString, "interface", iface)
// }
}
}
// Ensure the address exists on the interface before attempting to ARP
// if instance.network.HasEndpoints() {
if added, err := instance.network.AddIP(true); err != nil {
log.Warn(err.Error())
} else if added {
log.Warn("Re-applied the VIP configuration", "ip", ipString, "interface", iface)
}
// }
if vip.IsIPv6(ipString) {
// Gratuitous NDP, will broadcast new MAC <-> IPv6 address
if instance.ndp == nil {
log.Error("NDP responder was not created")
} else {
err := instance.ndp.SendGratuitous(ipString)
if err != nil {
log.Warn(err.Error())
}
}
} else {
// Gratuitous ARP, will broadcast to new MAC <-> IPv4 address
err := vip.ARPSendGratuitous(ipString, iface)
if err != nil {
log.Warn(err.Error())
}
}
}

88
pkg/backend/backend.go Normal file
View File

@@ -0,0 +1,88 @@
package backend
import (
"fmt"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/k8s"
"github.com/kube-vip/kube-vip/pkg/utils"
"github.com/kube-vip/kube-vip/pkg/vip"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
type Entry struct {
Addr string
Port uint16
IsLocal bool
}
type Map map[Entry]bool
func (e *Entry) Check() bool {
var client *kubernetes.Clientset
var err error
var config *rest.Config
adminConfigPath := "/etc/kubernetes/admin.conf"
// TODO: add one more switch case of homeConfigPath if there is such scenario in future
// homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config")
var k8sAddr string
if vip.IsIPv4(e.Addr) {
k8sAddr = fmt.Sprintf("%s:%v", e.Addr, e.Port)
} else {
k8sAddr = fmt.Sprintf("[%s]:%v", e.Addr, e.Port)
}
switch {
case utils.FileExists(adminConfigPath):
config, err = k8s.NewRestConfig(adminConfigPath, false, k8sAddr)
if err != nil {
log.Error("create k8s REST config", "path", adminConfigPath, "err", err)
return false
}
default:
config, err = k8s.NewRestConfig("", true, k8sAddr)
if err != nil {
log.Error("create k8s REST config", "err", err)
return false
}
}
client, err = k8s.NewClientset(config)
if err != nil {
log.Error("create k8s client", "err", err)
return false
}
_, err = client.DiscoveryClient.ServerVersion()
if err != nil {
log.Error("discover k8s version", "err", err)
return false
}
return true
}
func Watch(tickAction func(), interval int, stop chan struct{}) {
if interval <= 0 {
interval = 5
}
ticker := time.NewTicker(time.Second * time.Duration(interval))
defer ticker.Stop()
for {
select {
case <-stop:
ticker.Stop()
return
case <-ticker.C:
ticker.Stop()
tickAction()
ticker.Reset(time.Second * time.Duration(interval))
}
}
}

48
pkg/bgp/hosts.go Normal file
View File

@@ -0,0 +1,48 @@
package bgp
import (
"context"
"fmt"
"net"
api "github.com/osrg/gobgp/v3/api"
)
// AddHost will update peers of a host
func (b *Server) AddHost(addr string) (err error) {
ip, _, err := net.ParseCIDR(addr)
if err != nil {
return err
}
p := b.getPath(ip)
if p == nil {
return fmt.Errorf("failed to get path for %v", ip)
}
_, err = b.s.AddPath(context.Background(), &api.AddPathRequest{
Path: p,
})
if err != nil {
return err
}
return
}
// DelHost will inform peers to remove a host
func (b *Server) DelHost(addr string) (err error) {
ip, _, err := net.ParseCIDR(addr)
if err != nil {
return err
}
p := b.getPath(ip)
if p == nil {
return
}
return b.s.DeletePath(context.Background(), &api.DeletePathRequest{
Path: p,
})
}

341
pkg/bgp/peers.go Normal file
View File

@@ -0,0 +1,341 @@
package bgp
import (
"context"
"fmt"
"net"
"strconv"
"strings"
//nolint
"github.com/kube-vip/kube-vip/pkg/vip"
api "github.com/osrg/gobgp/v3/api"
"github.com/osrg/gobgp/v3/pkg/server"
"google.golang.org/protobuf/types/known/anypb"
)
// AddPeer will add peers to the BGP configuration
func (b *Server) AddPeer(peer Peer) (err error) {
p := &api.Peer{
Conf: &api.PeerConf{
NeighborAddress: peer.Address,
PeerAsn: peer.AS,
AuthPassword: peer.Password,
},
Timers: &api.Timers{
Config: &api.TimersConfig{
ConnectRetry: 10,
HoldTime: b.c.HoldTime,
KeepaliveInterval: b.c.KeepaliveInterval,
},
},
// This enables routes to be sent to routers across multiple hops
EbgpMultihop: &api.EbgpMultihop{
Enabled: peer.MultiHop,
MultihopTtl: 50,
},
Transport: &api.Transport{
MtuDiscovery: true,
RemoteAddress: peer.Address,
RemotePort: uint32(179),
},
}
if b.c.MpbgpNexthop != "" {
p.AfiSafis = []*api.AfiSafi{
{
Config: &api.AfiSafiConfig{
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_UNICAST,
},
Enabled: true,
},
},
{
Config: &api.AfiSafiConfig{
Family: &api.Family{
Afi: api.Family_AFI_IP6,
Safi: api.Family_SAFI_UNICAST,
},
Enabled: true,
},
},
}
peer.setMpbgpOptions(b.c)
ipv4Address, ipv6Address, err := peer.findMpbgpAddresses(p, b.c)
if err != nil {
return fmt.Errorf("failed to get MP-BGP addresses: %w", err)
}
mask := "128"
address := ipv4Address
family := api.Family_AFI_IP
if vip.IsIPv4(p.Conf.NeighborAddress) {
mask = "32"
address = ipv6Address
family = api.Family_AFI_IP6
}
err = b.s.AddDefinedSet(context.Background(), &api.AddDefinedSetRequest{
DefinedSet: &api.DefinedSet{
DefinedType: api.DefinedType_NEIGHBOR,
Name: fmt.Sprintf("peer-%s", p.Conf.NeighborAddress),
List: []string{fmt.Sprintf("%s/%s", p.Conf.NeighborAddress, mask)},
},
})
if err != nil {
return fmt.Errorf("failed to add defined set: %v", err)
}
if address != "" {
if err := insertPolicy(b.s, address, p, family); err != nil {
return fmt.Errorf("failed to add policy: %w", err)
}
}
} else {
if b.c.SourceIP != "" {
p.Transport.LocalAddress = b.c.SourceIP
}
if b.c.SourceIF != "" {
p.Transport.BindInterface = b.c.SourceIF
}
}
if err := b.s.AddPeer(context.Background(), &api.AddPeerRequest{Peer: p}); err != nil {
return fmt.Errorf("failed to add peer: %v", err)
}
return nil
}
func (b *Server) getPath(ip net.IP) (path *api.Path) {
isV6 := ip.To4() == nil
//nolint
originAttr, _ := anypb.New(&api.OriginAttribute{
Origin: 0,
})
if !isV6 {
//nolint
nlri, _ := anypb.New(&api.IPAddressPrefix{
Prefix: ip.String(),
PrefixLen: 32,
})
//nolint
nhAttr, _ := anypb.New(&api.NextHopAttribute{
NextHop: "0.0.0.0", // gobgp will fill this
})
path = &api.Path{
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_UNICAST,
},
Nlri: nlri,
Pattrs: []*anypb.Any{originAttr, nhAttr},
}
} else {
//nolint
nlri, _ := anypb.New(&api.IPAddressPrefix{
Prefix: ip.String(),
PrefixLen: 128,
})
v6Family := &api.Family{
Afi: api.Family_AFI_IP6,
Safi: api.Family_SAFI_UNICAST,
}
//nolint
mpAttr, _ := anypb.New(&api.MpReachNLRIAttribute{
Family: v6Family,
NextHops: []string{"::"}, // gobgp will fill this
Nlris: []*anypb.Any{nlri},
})
path = &api.Path{
Family: v6Family,
Nlri: nlri,
Pattrs: []*anypb.Any{originAttr, mpAttr},
}
}
return
}
// ParseBGPPeerConfig - take a string and parses it into an array of peers
func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) {
peers := strings.Split(config, ",")
if len(peers) == 0 {
return nil, fmt.Errorf("no BGP Peer configurations found")
}
for x := range peers {
peerStr := peers[x]
config := strings.Split(peerStr, "/")
peerStr = config[0]
if peerStr == "" {
continue
}
isV6Peer := peerStr[0] == '['
address := ""
if isV6Peer {
addressEndPos := strings.IndexByte(peerStr, ']')
if addressEndPos == -1 {
return nil, fmt.Errorf("no matching ] found for IPv6 BGP Peer")
}
address = peerStr[1:addressEndPos]
peerStr = peerStr[addressEndPos+1:]
}
peer := strings.Split(peerStr, ":")
if len(peer) < 2 {
return nil, fmt.Errorf("mandatory peering params <host>:<AS> incomplete")
}
if !isV6Peer {
address = peer[0]
}
ASNumber, err := strconv.ParseUint(peer[1], 10, 32)
if err != nil {
return nil, fmt.Errorf("BGP Peer AS format error [%s]", peer[1])
}
password := ""
if len(peer) >= 3 {
password = peer[2]
}
multiHop := false
if len(peer) >= 4 {
multiHop, err = strconv.ParseBool(peer[3])
if err != nil {
return nil, fmt.Errorf("BGP MultiHop format error (true/false) [%s]", peer[1])
}
}
var port uint64
if len(peer) >= 5 {
port, err = strconv.ParseUint(peer[4], 10, 16)
if err != nil {
return nil, fmt.Errorf("BGP Peer AS format error [%s]", peer[1])
}
} else {
port = 179
}
var mpbgpNexthop, mpbgpIPv4, mpbgpIPv6 string
if len(config) > 1 {
configData := strings.Split(config[1], ";")
for _, cfg := range configData {
c := strings.Split(cfg, "=")
switch c[0] {
case "mpbgp_nexthop":
mpbgpNexthop = c[1]
case "mpbgp_ipv4":
mpbgpIPv4 = c[1]
case "mpbgp_ipv6":
mpbgpIPv6 = c[1]
default:
return nil, fmt.Errorf("peer configuration parameter '%s' is not supported", c[0])
}
}
}
peerConfig := Peer{
Address: address,
AS: uint32(ASNumber),
Port: uint16(port),
Password: password,
MultiHop: multiHop,
MpbgpNexthop: mpbgpNexthop,
MpbgpIPv4: mpbgpIPv4,
MpbgpIPv6: mpbgpIPv6,
}
bgpPeers = append(bgpPeers, peerConfig)
}
return
}
func insertPolicy(s *server.BgpServer, address string, p *api.Peer, family api.Family_Afi) error {
familyType := "v4"
if family == api.Family_AFI_IP6 {
familyType = "v6"
}
setName := fmt.Sprintf("peer-%s", p.Conf.NeighborAddress)
policyName := fmt.Sprintf("%s-%s", setName, familyType)
policy := &api.Policy{
Name: policyName,
Statements: []*api.Statement{
{
Conditions: &api.Conditions{
AfiSafiIn: []*api.Family{
{
Afi: family,
Safi: api.Family_SAFI_UNICAST,
},
},
NeighborSet: &api.MatchSet{
Type: api.MatchSet_ANY,
Name: setName,
},
},
Actions: &api.Actions{
RouteAction: api.RouteAction_ACCEPT,
Nexthop: &api.NexthopAction{
Address: address,
},
},
},
{
Conditions: &api.Conditions{
NeighborSet: &api.MatchSet{
Type: api.MatchSet_ANY,
Name: setName,
},
},
Actions: &api.Actions{
RouteAction: api.RouteAction_ACCEPT,
},
},
},
}
err := s.AddPolicy(context.Background(), &api.AddPolicyRequest{
Policy: policy,
})
if err != nil {
return fmt.Errorf("failed to add policy: %w", err)
}
err = s.AddPolicyAssignment(context.Background(), &api.AddPolicyAssignmentRequest{
Assignment: &api.PolicyAssignment{
Name: "global",
Direction: api.PolicyDirection_EXPORT,
Policies: []*api.Policy{
{
Name: policy.Name,
},
},
},
})
if err != nil {
return fmt.Errorf("failed to add policy assignment: %v", err)
}
return nil
}

54
pkg/bgp/peers_test.go Normal file
View File

@@ -0,0 +1,54 @@
package bgp
import (
"reflect"
"testing"
)
func TestParseBGPPeerConfig(t *testing.T) {
type args struct {
config string
}
tests := []struct {
name string
args args
wantBgpPeers []Peer
wantErr bool
}{
{
name: "IPv4, default port",
args: args{config: "192.168.0.10:65000::false,192.168.0.11:65000::false"},
wantBgpPeers: []Peer{
{Address: "192.168.0.10", Port: 179, AS: 65000, MultiHop: false},
{Address: "192.168.0.11", Port: 179, AS: 65000, MultiHop: false},
},
},
{
name: "IPv4, different port",
args: args{config: "192.168.0.10:65000::false:180,192.168.0.11:65000::false:190"},
wantBgpPeers: []Peer{
{Address: "192.168.0.10", Port: 180, AS: 65000, MultiHop: false},
{Address: "192.168.0.11", Port: 190, AS: 65000, MultiHop: false},
},
},
{
name: "IPv6, multi-protocol",
args: args{config: "[fd00:1111:2222:3333:c7d9:7235:6bf7:5d52]:65501::false/mpbgp_nexthop=auto_sourceif"},
wantBgpPeers: []Peer{
{Address: "fd00:1111:2222:3333:c7d9:7235:6bf7:5d52", Port: 179, AS: 65501, MultiHop: false, MpbgpNexthop: "auto_sourceif"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotBgpPeers, err := ParseBGPPeerConfig(tt.args.config)
if (err != nil) != tt.wantErr {
t.Errorf("ParseBGPPeerConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotBgpPeers, tt.wantBgpPeers) {
t.Errorf("ParseBGPPeerConfig() = %v, want %v", gotBgpPeers, tt.wantBgpPeers)
}
})
}
}

93
pkg/bgp/server.go Normal file
View File

@@ -0,0 +1,93 @@
package bgp
import (
"context"
"fmt"
"time"
log "log/slog"
api "github.com/osrg/gobgp/v3/api"
gobgp "github.com/osrg/gobgp/v3/pkg/server"
"github.com/prometheus/client_golang/prometheus"
)
// NewBGPServer takes a configuration and returns a running BGP server instance
func NewBGPServer(c *Config) (b *Server, err error) {
if c.AS == 0 {
return nil, fmt.Errorf("you need to provide AS")
}
if c.SourceIP != "" && c.SourceIF != "" {
return nil, fmt.Errorf("sourceIP and SourceIF are mutually exclusive")
}
if len(c.Peers) == 0 {
return nil, fmt.Errorf("you need to provide at least one peer")
}
b = &Server{
s: gobgp.NewBgpServer(),
c: c,
BGPSessionInfoGauge: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "kube_vip",
Subsystem: "manager",
Name: "bgp_session_info",
Help: "Display state of session by setting metric for label value with current state to 1",
}, []string{"state", "peer"}),
}
return
}
// Start starts the BGP server
func (b *Server) Start(peerStateChangeCallback func(*api.WatchEventResponse_PeerEvent)) (err error) {
go b.s.Serve()
if err = b.s.StartBgp(context.Background(), &api.StartBgpRequest{
Global: &api.Global{
Asn: b.c.AS,
RouterId: b.c.RouterID,
ListenPort: -1,
},
}); err != nil {
return
}
if err = b.s.WatchEvent(context.Background(), &api.WatchEventRequest{Peer: &api.WatchEventRequest_Peer{}}, func(r *api.WatchEventResponse) {
if p := r.GetPeer(); p != nil && p.Type == api.WatchEventResponse_PeerEvent_STATE {
log.Info("[BGP]", "peer", p.String())
if peerStateChangeCallback != nil {
peerStateChangeCallback(p)
}
}
}); err != nil {
return
}
for _, p := range b.c.Peers {
if err = b.AddPeer(p); err != nil {
return
}
}
if b.c.Zebra.Enabled {
if err = b.s.EnableZebra(context.Background(), &api.EnableZebraRequest{
Url: b.c.Zebra.URL,
Version: b.c.Zebra.Version,
SoftwareName: b.c.Zebra.SoftwareName,
}); err != nil {
log.Error(err.Error())
return
}
}
return
}
// Close will stop a running BGP Server
func (b *Server) Close() error {
ctx, cf := context.WithTimeout(context.Background(), 5*time.Second)
defer cf()
return b.s.StopBgp(ctx, &api.StopBgpRequest{})
}

145
pkg/bgp/types.go Normal file
View File

@@ -0,0 +1,145 @@
package bgp
import (
"fmt"
"net"
"github.com/kube-vip/kube-vip/pkg/vip"
api "github.com/osrg/gobgp/v3/api"
gobgp "github.com/osrg/gobgp/v3/pkg/server"
"github.com/prometheus/client_golang/prometheus"
"github.com/vishvananda/netlink"
)
// Peer defines a BGP Peer
type Peer struct {
Address string
Port uint16
AS uint32
Password string
MultiHop bool
MpbgpNexthop string
MpbgpIPv4 string
MpbgpIPv6 string
}
func (p *Peer) setMpbgpOptions(server *Config) {
if p.MpbgpNexthop == "" {
p.MpbgpNexthop = server.MpbgpNexthop
}
if p.MpbgpIPv4 == "" {
p.MpbgpIPv4 = server.MpbgpIPv4
}
if p.MpbgpIPv6 == "" {
p.MpbgpIPv6 = server.MpbgpIPv6
}
}
func (p *Peer) findMpbgpAddresses(ap *api.Peer, server *Config) (string, string, error) {
var ipv4Address, ipv6Address string
switch p.MpbgpNexthop {
case "fixed":
ap.Transport.LocalAddress = server.SourceIP
if p.MpbgpIPv4 == "" && p.MpbgpIPv6 == "" {
return "", "", fmt.Errorf("to use MP-BGP with fixed address at least one IPv4 or IPv6 address has to be provided [current - IPv4: %s, IPv6: %s]",
p.MpbgpIPv4, p.MpbgpIPv6)
}
if p.MpbgpIPv4 != "" {
if net.ParseIP(p.MpbgpIPv4) == nil {
return "", "", fmt.Errorf("provided address '%s' is not a valid IPv4 address", p.MpbgpIPv4)
}
}
if p.MpbgpIPv6 != "" {
if net.ParseIP(p.MpbgpIPv6) == nil {
return "", "", fmt.Errorf("provided address '%s' is not a valid IPv6 address", p.MpbgpIPv6)
}
}
ipv4Address = p.MpbgpIPv4
ipv6Address = p.MpbgpIPv6
case "auto_sourceip":
ap.Transport.LocalAddress = server.SourceIP
// Resolve the local interface by SourceIP
iface, err := vip.GetInterfaceByIP(server.SourceIP)
if err != nil {
return "", "", fmt.Errorf("failed to get interface by IP: %v", err)
}
if vip.IsIPv4(server.SourceIP) {
// Get the non link-local IPv6 address on that interface
ipv6Address, err = vip.GetNonLinkLocalIP(iface, netlink.FAMILY_V6)
if err != nil {
return "", "", fmt.Errorf("failed to get non link-local IPv6 address: %v", err)
}
} else {
// Get the non link-local IPv4 address on that interface
ipv4Address, err = vip.GetNonLinkLocalIP(iface, netlink.FAMILY_V4)
if err != nil {
return "", "", fmt.Errorf("failed to get non link-local IPv4 address: %v", err)
}
}
case "auto_sourceif":
ap.Transport.BindInterface = server.SourceIF
iface, err := netlink.LinkByName(server.SourceIF)
if err != nil {
return "", "", fmt.Errorf("failed to get interface by name: %v", err)
}
// Get the non link-local IPv4 address on that interface
ipv4Address, err = vip.GetNonLinkLocalIP(&iface, netlink.FAMILY_V4)
if err != nil {
return "", "", fmt.Errorf("failed to get non link-local IPv4 address: %v", err)
}
// Get the non link-local IPv6 address on that interface
ipv6Address, err = vip.GetNonLinkLocalIP(&iface, netlink.FAMILY_V6)
if err != nil {
return "", "", fmt.Errorf("failed to get non link-local IPv6 address: %v", err)
}
default:
return "", "", fmt.Errorf("option %s for MP-BPG nexthop is not supported", server.MpbgpNexthop)
}
return ipv4Address, ipv6Address, nil
}
// Config defines the BGP server configuration
type Config struct {
AS uint32
RouterID string
SourceIP string
SourceIF string
MpbgpNexthop string
MpbgpIPv4 string
MpbgpIPv6 string
HoldTime uint64
KeepaliveInterval uint64
Peers []Peer
Zebra ZebraConfig
}
// Defines Zebra connection configuration. More on the topic - https://github.com/osrg/gobgp/blob/master/docs/sources/zebra.md#configuration
type ZebraConfig struct {
Enabled bool
URL string
Version uint32
SoftwareName string
}
// Server manages a server object
type Server struct {
s *gobgp.BgpServer
c *Config
// This is a prometheus gauge indicating the state of the sessions.
// 1 means "ESTABLISHED", 0 means "NOT ESTABLISHED"
BGPSessionInfoGauge *prometheus.GaugeVec
}

View File

@@ -1,49 +1,80 @@
package cluster
import (
"github.com/plunder-app/kube-vip/pkg/kubevip"
"github.com/plunder-app/kube-vip/pkg/vip"
)
"sync"
const leaderLogcount = 5
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/arp"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/networkinterface"
"github.com/kube-vip/kube-vip/pkg/vip"
)
// Cluster - The Cluster object manages the state of the cluster for a particular node
type Cluster struct {
stateMachine FSM
stop chan bool
completed chan bool
network *vip.Network
stop chan bool
completed chan bool
once sync.Once
Network []vip.Network
arpMgr *arp.Manager
}
// InitCluster - Will attempt to initialise all of the required settings for the cluster
func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) {
// TODO - Check for root (needed to netlink)
var network *vip.Network
func InitCluster(c *kubevip.Config, disableVIP bool, intfMgr *networkinterface.Manager, arpMgr *arp.Manager) (*Cluster, error) {
var networks []vip.Network
var err error
if !disableVIP {
// Start the Virtual IP Networking configuration
network, err = startNetworking(c)
networks, err = startNetworking(c, intfMgr)
if err != nil {
return nil, err
}
}
// Initialise the Cluster structure
newCluster := &Cluster{
network: network,
Network: networks,
arpMgr: arpMgr,
}
log.Debug("service security", "enabled", c.EnableServiceSecurity)
return newCluster, nil
}
func startNetworking(c *kubevip.Config) (*vip.Network, error) {
network, err := vip.NewConfig(c.VIP, c.Interface)
if err != nil {
// log.WithFields(log.Fields{"error": err}).Error("Network failure")
func startNetworking(c *kubevip.Config, intfMgr *networkinterface.Manager) ([]vip.Network, error) {
address := c.VIP
// os.Exit(-1)
return nil, err
if c.Address != "" {
address = c.Address
}
return &network, nil
addresses := vip.Split(address)
networks := []vip.Network{}
for _, addr := range addresses {
network, err := vip.NewConfig(addr, c.Interface, c.LoInterfaceGlobalScope, c.VIPSubnet, c.DDNS, c.RoutingTableID,
c.RoutingTableType, c.RoutingProtocol, c.DNSMode, c.LoadBalancerForwardingMethod, c.IptablesBackend,
c.EnableLoadBalancer, c.EnableServiceSecurity, intfMgr)
if err != nil {
return nil, err
}
networks = append(networks, network...)
}
return networks, nil
}
// Stop - Will stop the Cluster and release VIP if needed
func (cluster *Cluster) Stop() {
// Close the stop channel, which will shut down the VIP (if needed)
if cluster.stop != nil {
cluster.once.Do(func() { // Ensure that the close channel can only ever be called once
close(cluster.stop)
})
}
// Wait until the completed channel is closed, signallign all shutdown tasks completed
<-cluster.completed
}

View File

@@ -0,0 +1,28 @@
package cluster
import (
"context"
"github.com/kube-vip/kube-vip/pkg/vip"
)
// StartDDNS should start go routine for dhclient to hold the lease for the IP
// StartDDNS should wait until IP is allocated from DHCP, set it to cluster.Network
// so the OnStartedLeading can continue to configure the VIP initially
// during runtime if IP changes, startDDNS don't have to do reconfigure because
// dnsUpdater already have the functionality to keep trying resolve the IP
// and update the VIP configuration if it changes
func (cluster *Cluster) StartDDNS(ctx context.Context) error {
for i := range cluster.Network {
ddnsMgr := vip.NewDDNSManager(ctx, cluster.Network[i])
ip, err := ddnsMgr.Start()
if err != nil {
return err
}
if err = cluster.Network[i].SetIP(ip); err != nil {
return err
}
}
return nil
}

View File

@@ -1,305 +0,0 @@
package cluster
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/plunder-app/kube-vip/pkg/kubevip"
"github.com/plunder-app/kube-vip/pkg/loadbalancer"
"github.com/plunder-app/kube-vip/pkg/vip"
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
)
const plunderLock = "plunder-lock"
const namespace = "kube-system"
// Manager degines the manager of the load-balancing services
type Manager struct {
clientSet *kubernetes.Clientset
}
// NewManager will create a new managing object
func NewManager(path string, inCluster bool) (*Manager, error) {
var clientset *kubernetes.Clientset
if inCluster {
// This will attempt to load the configuration when running within a POD
cfg, err := rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error())
}
clientset, err = kubernetes.NewForConfig(cfg)
if err != nil {
return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error())
}
// use the current context in kubeconfig
} else {
if path == "" {
path = filepath.Join(os.Getenv("HOME"), ".kube", "config")
}
config, err := clientcmd.BuildConfigFromFlags("", path)
if err != nil {
panic(err.Error())
}
// We modify the config so that we can always speak to the correct host
id, err := os.Hostname()
if err != nil {
return nil, err
}
// TODO - we need to make the host/port configurable
config.Host = fmt.Sprintf("%s:6443", id)
clientset, err = kubernetes.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error())
}
}
return &Manager{
clientSet: clientset,
}, nil
}
// StartLeaderCluster - Begins a running instance of the Raft cluster
func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error {
id, err := os.Hostname()
if err != nil {
return err
}
log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", namespace, plunderLock, id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Name: plunderLock,
Namespace: namespace,
},
Client: sm.clientSet.CoordinationV1(),
LockConfig: resourcelock.ResourceLockConfig{
Identity: id,
},
}
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// use a Go context so we can tell the arp loop code when we
// want to step down
ctxArp, cancelArp := context.WithCancel(context.Background())
defer cancelArp()
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
signalChan := make(chan os.Signal, 1)
// Add Notification for Userland interrupt
signal.Notify(signalChan, syscall.SIGINT)
// Add Notification for SIGTERM (sent from Kubernetes)
signal.Notify(signalChan, syscall.SIGTERM)
// Add Notification for SIGKILL (sent from Kubernetes)
signal.Notify(signalChan, syscall.SIGKILL)
go func() {
<-signalChan
log.Info("Received termination, signaling shutdown")
// Cancel the context, which will in turn cancel the leadership
cancel()
// Cancel the arp context, which will in turn stop any broadcasts
}()
// (attempt to) Remove the virtual IP, incase it already exists
cluster.network.DeleteIP()
// Managers for Vip load balancers and none-vip loadbalancers
nonVipLB := loadbalancer.LBManager{}
VipLB := loadbalancer.LBManager{}
if c.EnableLoadBalancer {
// Iterate through all Configurations
if len(c.LoadBalancers) != 0 {
for x := range c.LoadBalancers {
// If the load balancer doesn't bind to the VIP
if c.LoadBalancers[x].BindToVip == false {
err = nonVipLB.Add("", &c.LoadBalancers[x])
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
}
}
}
}
}
// start the leader election code loop
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
Lock: lock,
// IMPORTANT: you MUST ensure that any code you have that
// is protected by the lease must terminate **before**
// you call cancel. Otherwise, you could have a background
// loop still running and another process could
// get elected before your background loop finished, violating
// the stated goal of the lease.
ReleaseOnCancel: true,
LeaseDuration: 3 * time.Second,
RenewDeadline: 2 * time.Second,
RetryPeriod: 1 * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
// we're notified when we start
log.Info("This node is starting with leadership of the cluster")
err = cluster.network.AddIP()
if err != nil {
log.Warnf("%v", err)
}
if c.EnablePacket {
packetClient, err := packngo.NewClient()
if err != nil {
log.Error(err)
}
projects, _, err := packetClient.Projects.List(nil)
if err != nil {
log.Error(err)
}
for _, p := range projects {
log.Println(p.ID, p.Name)
// Find our project
if p.Name == c.PacketProject {
ips, _, _ := packetClient.ProjectIPs.List(p.ID)
for _, ip := range ips {
// Find the device id for our EIP
if ip.Address == c.VIP {
log.Infof("Found EIP ->%s ID -> %s\n", ip.Address, ip.ID)
if len(ip.Assignments) != 0 {
hrefID := strings.Replace(ip.Assignments[0].Href, "/ips/", "", -1)
packetClient.DeviceIPs.Unassign(hrefID)
}
}
}
// Go through devices
dev, _, _ := packetClient.Devices.List(p.ID, &packngo.ListOptions{})
for _, d := range dev {
if d.Hostname == id {
log.Infof("Assigning EIP to -> %s\n", d.Hostname)
_, _, err := packetClient.DeviceIPs.Assign(d.ID, &packngo.AddressStruct{
Address: c.VIP,
})
if err != nil {
log.Errorln(err)
}
}
}
}
}
}
if c.EnableLoadBalancer {
// Once we have the VIP running, start the load balancer(s) that bind to the VIP
for x := range c.LoadBalancers {
if c.LoadBalancers[x].BindToVip == true {
err = VipLB.Add(c.VIP, &c.LoadBalancers[x])
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
// Stop all load balancers associated with the VIP
err = VipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
}
err = cluster.network.DeleteIP()
if err != nil {
log.Warnf("%v", err)
}
}
}
}
}
if c.GratuitousARP == true {
ctxArp, cancelArp = context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done(): // if cancel() execute
return
default:
// Gratuitous ARP, will broadcast to new MAC <-> IP
err = vip.ARPSendGratuitous(c.VIP, c.Interface)
if err != nil {
log.Warnf("%v", err)
}
}
time.Sleep(3 * time.Second)
}
}(ctxArp)
}
},
OnStoppedLeading: func() {
// we can do cleanup here
log.Info("This node is becoming a follower within the cluster")
// Stop the Arp context if it is running
cancelArp()
// Stop all load balancers associated with the VIP
err = VipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
}
err = cluster.network.DeleteIP()
if err != nil {
log.Warnf("%v", err)
}
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
log.Infof("Node [%s] is assuming leadership of the cluster", identity)
if identity == id {
// We have the lock
}
},
},
})
//<-signalChan
log.Infof("Shutting down Kube-Vip Leader Election cluster")
// Force a removal of the VIP (ignore the error if we don't have it)
cluster.network.DeleteIP()
return nil
}

View File

@@ -0,0 +1,390 @@
package cluster
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/etcd"
"github.com/kube-vip/kube-vip/pkg/k8s"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/loadbalancer"
log "log/slog"
clientv3 "go.etcd.io/etcd/client/v3"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
watchtools "k8s.io/client-go/tools/watch"
)
// Manager degines the manager of the load-balancing services
type Manager struct {
KubernetesClient *kubernetes.Clientset
RetryWatcherClient *kubernetes.Clientset
// This channel is used to signal a shutdown
SignalChan chan os.Signal
EtcdClient *clientv3.Client
}
// NewManager will create a new managing object
func NewManager(path string, inCluster bool, port int) (*Manager, error) {
var hostname string
// If inCluster is set then it will likely have started as a static pod or won't have the
// VIP up before trying to connect to the API server, we set the API endpoint to this machine to
// ensure connectivity. Else if the path passed is empty and not running in the cluster,
// attempt to look for a kubeconfig in the default HOME dir.
hostname = fmt.Sprintf("kubernetes:%v", port)
if len(path) == 0 && !inCluster {
path = filepath.Join(os.Getenv("HOME"), ".kube", "config")
// We modify the config so that we can always speak to the correct host
id, err := os.Hostname()
if err != nil {
return nil, err
}
hostname = fmt.Sprintf("%s:%v", id, port)
}
config, err := k8s.NewRestConfig(path, inCluster, hostname)
if err != nil {
return nil, fmt.Errorf("failed to create k8s REST config: %w", err)
}
clientset, err := k8s.NewClientset(config)
if err != nil {
return nil, fmt.Errorf("error creating a new k8s clientset: %v", err)
}
rwConfig, err := k8s.NewRestConfig(path, inCluster, hostname)
if err != nil {
return nil, fmt.Errorf("failed to create k8s REST config for retryClientSet: %w", err)
}
rwConfig.Timeout = 0 // empty value to disable the timeout
rwClientSet, err := k8s.NewClientset(rwConfig)
if err != nil {
return nil, fmt.Errorf("failed to create k8s client for retry watcher: %w", err)
}
return &Manager{
KubernetesClient: clientset,
RetryWatcherClient: rwClientSet,
}, nil
}
// StartCluster - Begins a running instance of the Leader Election cluster
func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error {
var err error
log.Info("cluster membership", "namespace", c.Namespace, "lock", c.LeaseName, "id", c.NodeName)
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// use a Go context so we can tell the arp loop code when we
// want to step down
ctxArp, cancelArp := context.WithCancel(context.Background())
defer cancelArp()
// use a Go context so we can tell the dns loop code when we
// want to step down
ctxDNS, cancelDNS := context.WithCancel(context.Background())
defer cancelDNS()
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
signalChan := make(chan os.Signal, 1)
// Add Notification for Userland interrupt
signal.Notify(signalChan, syscall.SIGINT)
// Add Notification for SIGTERM (sent from Kubernetes)
signal.Notify(signalChan, syscall.SIGTERM)
go func() {
<-signalChan
log.Info("Received termination, signaling cluster shutdown")
// Cancel the context, which will in turn cancel the leadership
cancel()
// Cancel the arp context, which will in turn stop any broadcasts
}()
// (attempt to) Remove the virtual IP, in case it already exists
for i := range cluster.Network {
deleted, err := cluster.Network[i].DeleteIP()
if err != nil {
log.Error("could not delete virtualIP", "err", err)
}
if deleted {
log.Info("deleted address", "IP", cluster.Network[i].IP(), "interface", cluster.Network[i].Interface())
}
}
// Defer a function to check if the bgpServer has been created and if so attempt to close it
defer func() {
if bgpServer != nil {
bgpServer.Close()
}
}()
if c.EnableBGP && bgpServer == nil {
// Lets start BGP
log.Info("Starting the BGP server to advertise VIP routes to VGP peers")
bgpServer, err = bgp.NewBGPServer(&c.BGPConfig)
if err != nil {
log.Error("new BGP server", "err", err)
}
if err := bgpServer.Start(nil); err != nil {
log.Error("starting BGP server", "err", err)
}
}
run := &runConfig{
config: c,
leaseID: c.NodeName,
sm: sm,
onStartedLeading: func(ctx context.Context) { //nolint TODO: potential clean code
// As we're leading lets start the vip service
err := cluster.vipService(ctxArp, ctxDNS, c, sm, bgpServer, cancel)
if err != nil {
log.Error("starting VIP service on leader", "err", err)
}
},
onStoppedLeading: func() {
// we can do cleanup here
log.Info("This node is becoming a follower within the cluster")
// Stop the dns context
cancelDNS()
// Stop the Arp context if it is running
cancelArp()
// Stop the BGP server
if bgpServer != nil {
err := bgpServer.Close()
if err != nil {
log.Warn("close BGP server", "err", err)
}
}
for i := range cluster.Network {
deleted, err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warn("delete VIP", "err", err)
}
if deleted {
log.Info("deleted address", "IP", cluster.Network[i].IP(), "interface", cluster.Network[i].Interface())
}
}
log.Error("lost leadership, restarting kube-vip")
panic("") // TODO - we could also return here
},
onNewLeader: func(identity string) {
// we're notified when new leader elected
log.Info("New leader", "leader", identity)
},
}
switch c.LeaderElectionType {
case "kubernetes", "":
cluster.runKubernetesLeaderElectionOrDie(ctx, run)
case "etcd":
cluster.runEtcdLeaderElectionOrDie(ctx, run)
default:
log.Info(fmt.Sprintf("LeaderElectionMode %s not supported, exiting", c.LeaderElectionType))
}
return nil
}
type runConfig struct {
config *kubevip.Config
leaseID string
sm *Manager
// onStartedLeading is called when this member starts leading.
onStartedLeading func(context.Context)
// onStoppedLeading is called when this member stops leading.
onStoppedLeading func()
// onNewLeader is called when the client observes a leader that is
// not the previously observed leader. This includes the first observed
// leader when the client starts.
onNewLeader func(identity string)
}
func (cluster *Cluster) runKubernetesLeaderElectionOrDie(ctx context.Context, run *runConfig) {
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Name: run.config.LeaseName,
Namespace: run.config.Namespace,
Annotations: run.config.LeaseAnnotations,
},
Client: run.sm.KubernetesClient.CoordinationV1(),
LockConfig: resourcelock.ResourceLockConfig{
Identity: run.leaseID,
},
}
// start the leader election code loop
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
Lock: lock,
// IMPORTANT: you MUST ensure that any code you have that
// is protected by the lease must terminate **before**
// you call cancel. Otherwise, you could have a background
// loop still running and another process could
// get elected before your background loop finished, violating
// the stated goal of the lease.
ReleaseOnCancel: true,
LeaseDuration: time.Duration(run.config.LeaseDuration) * time.Second,
RenewDeadline: time.Duration(run.config.RenewDeadline) * time.Second,
RetryPeriod: time.Duration(run.config.RetryPeriod) * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: run.onStartedLeading,
OnStoppedLeading: run.onStoppedLeading,
OnNewLeader: run.onNewLeader,
},
})
}
func (cluster *Cluster) runEtcdLeaderElectionOrDie(ctx context.Context, run *runConfig) {
etcd.RunElectionOrDie(ctx, &etcd.LeaderElectionConfig{
EtcdConfig: etcd.ClientConfig{Client: run.sm.EtcdClient},
Name: run.config.LeaseName,
MemberID: run.leaseID,
LeaseDurationSeconds: int64(run.config.LeaseDuration),
Callbacks: etcd.LeaderCallbacks{
OnStartedLeading: run.onStartedLeading,
OnStoppedLeading: run.onStoppedLeading,
OnNewLeader: run.onNewLeader,
},
})
}
func (sm *Manager) NodeWatcher(ctxArp context.Context, lb *loadbalancer.IPVSLoadBalancer, port uint16) error {
// Use a restartable watcher, as this should help in the event of etcd or timeout issues
log.Info("Kube-Vip is watching nodes for control-plane labels")
listOptions := metav1.ListOptions{
LabelSelector: "node-role.kubernetes.io/control-plane",
}
rw, err := watchtools.NewRetryWatcherWithContext(ctxArp, "1", &cache.ListWatch{
WatchFunc: func(_ metav1.ListOptions) (watch.Interface, error) {
return sm.RetryWatcherClient.CoreV1().Nodes().Watch(context.Background(), listOptions)
},
})
if err != nil {
return fmt.Errorf("error creating label watcher: %s", err.Error())
}
go func() {
<-sm.SignalChan
log.Info("Received termination, signaling shutdown")
// Cancel the context
rw.Stop()
}()
ch := rw.ResultChan()
// defer rw.Stop()
for event := range ch {
// We need to inspect the event and get ResourceVersion out of it
switch event.Type {
case watch.Added, watch.Modified:
node, ok := event.Object.(*v1.Node)
if !ok {
return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher")
}
// Find the node IP address (this isn't foolproof)
for x := range node.Status.Addresses {
if node.Status.Addresses[x].Type == v1.NodeInternalIP {
if checkIfNodeIsReady(node) {
err = lb.AddBackend(node.Status.Addresses[x].Address, port)
if err != nil {
log.Error("add IPVS backend", "err", err)
}
} else {
err = lb.RemoveBackend(node.Status.Addresses[x].Address, port)
if err != nil {
log.Error("remove IPVS backend", "err", err)
}
}
}
}
case watch.Deleted:
node, ok := event.Object.(*v1.Node)
if !ok {
return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher")
}
// Find the node IP address (this isn't foolproof)
for x := range node.Status.Addresses {
if node.Status.Addresses[x].Type == v1.NodeInternalIP {
err = lb.RemoveBackend(node.Status.Addresses[x].Address, port)
if err != nil {
log.Error("Del IPVS backend", "err", err)
}
}
}
log.Info("Node deleted", "name", node.Name)
case watch.Bookmark:
// Un-used
case watch.Error:
log.Error("Error attempting to watch Kubernetes Nodes")
// This round trip allows us to handle unstructured status
errObject := apierrors.FromObject(event.Object)
statusErr, ok := errObject.(*apierrors.StatusError)
if !ok {
log.Error(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object))
}
status := statusErr.ErrStatus
log.Error("watcher", "status", status)
default:
}
}
log.Info("Exiting Node watcher")
return nil
}
func checkIfNodeIsReady(node *v1.Node) bool {
if node == nil {
return false
}
for _, condition := range node.Status.Conditions {
if condition.Type == v1.NodeReady {
if condition.Status == v1.ConditionTrue {
return true
}
}
}
return false
}

View File

@@ -1,296 +0,0 @@
package cluster
import (
"fmt"
"net"
"time"
"github.com/hashicorp/raft"
"github.com/plunder-app/kube-vip/pkg/kubevip"
"github.com/plunder-app/kube-vip/pkg/loadbalancer"
"github.com/plunder-app/kube-vip/pkg/vip"
log "github.com/sirupsen/logrus"
)
// StartRaftCluster - Begins a running instance of the Raft cluster
func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error {
// Create local configuration address
localAddress := fmt.Sprintf("%s:%d", c.LocalPeer.Address, c.LocalPeer.Port)
// Begin the Raft configuration
config := raft.DefaultConfig()
config.LocalID = raft.ServerID(c.LocalPeer.ID)
logger := log.StandardLogger().Writer()
config.LogOutput = logger
// Initialize communication
address, err := net.ResolveTCPAddr("tcp", localAddress)
if err != nil {
return err
}
// Create transport
transport, err := raft.NewTCPTransport(localAddress, address, 3, 10*time.Second, logger)
if err != nil {
return err
}
// Create Raft structures
snapshots := raft.NewInmemSnapshotStore()
logStore := raft.NewInmemStore()
stableStore := raft.NewInmemStore()
// Cluster configuration
configuration := raft.Configuration{}
// Add Local Peer
configuration.Servers = append(configuration.Servers, raft.Server{
ID: raft.ServerID(c.LocalPeer.ID),
Address: raft.ServerAddress(fmt.Sprintf("%s:%d", c.LocalPeer.Address, c.LocalPeer.Port))})
// If we want to start a node as leader then we will not add any remote peers, this will leave this as a cluster of one
// The remotePeers will add themselves to the cluster as they're added
if c.StartAsLeader != true {
for x := range c.RemotePeers {
// Make sure that we don't add in this server twice
if c.LocalPeer.Address != c.RemotePeers[x].Address {
// Build the address from the peer configuration
peerAddress := fmt.Sprintf("%s:%d", c.RemotePeers[x].Address, c.RemotePeers[x].Port)
// Set this peer into the raft configuration
configuration.Servers = append(configuration.Servers, raft.Server{
ID: raft.ServerID(c.RemotePeers[x].ID),
Address: raft.ServerAddress(peerAddress)})
}
}
log.Info("This node will attempt to start as Follower")
} else {
log.Info("This node will attempt to start as Leader")
}
// Bootstrap cluster
if err := raft.BootstrapCluster(config, logStore, stableStore, snapshots, transport, configuration); err != nil {
return err
}
// Create RAFT instance
raftServer, err := raft.NewRaft(config, cluster.stateMachine, logStore, stableStore, snapshots, transport)
if err != nil {
return err
}
cluster.stop = make(chan bool, 1)
cluster.completed = make(chan bool, 1)
ticker := time.NewTicker(time.Second)
isLeader := c.StartAsLeader
// (attempt to) Remove the virtual IP, incase it already exists
cluster.network.DeleteIP()
// leader log broadcast - this counter is used to stop flooding STDOUT with leader log entries
var leaderbroadcast int
// Managers for Vip load balancers and none-vip loadbalancers
nonVipLB := loadbalancer.LBManager{}
VipLB := loadbalancer.LBManager{}
// Iterate through all Configurations
for x := range c.LoadBalancers {
// If the load balancer doesn't bind to the VIP
if c.LoadBalancers[x].BindToVip == false {
err = nonVipLB.Add("", &c.LoadBalancers[x])
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
}
}
}
// On a cold start the node will sleep for 5 seconds to ensure that leader elections are complete
log.Infoln("This instance will wait approximately 5 seconds, from cold start to ensure cluster elections are complete")
time.Sleep(time.Second * 5)
go func() {
for {
if c.AddPeersAsBackends == true {
// Get addresses and change backends
// c.LoadBalancers[0].Backends
// for x := range raftServer.GetConfiguration().Configuration().Servers {
// raftServer.GetConfiguration().Configuration().Servers[x].Address
// }
}
// Broadcast the current leader on this node if it's the correct time (every leaderLogcount * time.Second)
if leaderbroadcast == leaderLogcount {
log.Infof("The Node [%s] is leading", raftServer.Leader())
// Reset the timer
leaderbroadcast = 0
// ensure that if this node is the leader, it is set as the leader
if localAddress == string(raftServer.Leader()) {
// Re-broadcast arp to ensure network stays up to date
if c.GratuitousARP == true {
// Gratuitous ARP, will broadcast to new MAC <-> IP
err = vip.ARPSendGratuitous(c.VIP, c.Interface)
if err != nil {
log.Warnf("%v", err)
}
}
if !isLeader {
log.Infoln("This node is leading, but isnt the leader (correcting)")
isLeader = true
}
} else {
// (attempt to) Remove the virtual IP, incase it already exists to keep nodes clean
cluster.network.DeleteIP()
isLeader = false
}
}
leaderbroadcast++
select {
case leader := <-raftServer.LeaderCh():
log.Infoln("New Election event")
if leader {
isLeader = true
log.Info("This node is assuming leadership of the cluster")
err = cluster.network.AddIP()
if err != nil {
log.Warnf("%v", err)
}
// Once we have the VIP running, start the load balancer(s) that bind to the VIP
for x := range c.LoadBalancers {
if c.LoadBalancers[x].BindToVip == true {
err = VipLB.Add(c.VIP, &c.LoadBalancers[x])
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
log.Errorf("Dropping Leadership to another node in the cluster")
raftServer.LeadershipTransfer()
// Stop all load balancers associated with the VIP
err = VipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
}
err = cluster.network.DeleteIP()
if err != nil {
log.Warnf("%v", err)
}
}
}
}
if c.GratuitousARP == true {
// Gratuitous ARP, will broadcast to new MAC <-> IP
err = vip.ARPSendGratuitous(c.VIP, c.Interface)
if err != nil {
log.Warnf("%v", err)
}
}
} else {
isLeader = false
log.Info("This node is becoming a follower within the cluster")
// Stop all load balancers associated with the VIP
err = VipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
}
err = cluster.network.DeleteIP()
if err != nil {
log.Warnf("%v", err)
}
}
case <-ticker.C:
if isLeader {
result, err := cluster.network.IsSet()
if err != nil {
log.WithFields(log.Fields{"error": err, "ip": cluster.network.IP(), "interface": cluster.network.Interface()}).Error("Could not check ip")
}
if result == false {
log.Error("This node is leader and is adopting the virtual IP")
err = cluster.network.AddIP()
if err != nil {
log.Warnf("%v", err)
}
// Once we have the VIP running, start the load balancer(s) that bind to the VIP
for x := range c.LoadBalancers {
if c.LoadBalancers[x].BindToVip == true {
err = VipLB.Add(c.VIP, &c.LoadBalancers[x])
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
}
}
}
if c.GratuitousARP == true {
// Gratuitous ARP, will broadcast to new MAC <-> IP
err = vip.ARPSendGratuitous(c.VIP, c.Interface)
if err != nil {
log.Warnf("%v", err)
}
}
}
}
case <-cluster.stop:
log.Info("[RAFT] Stopping this node")
log.Info("[LOADBALANCER] Stopping load balancers")
// Stop all load balancers associated with the VIP
err = VipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
}
// Stop all load balancers associated with the Host
err = nonVipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
}
if isLeader {
log.Info("[VIP] Releasing the Virtual IP")
err = cluster.network.DeleteIP()
if err != nil {
log.Warnf("%v", err)
}
}
close(cluster.completed)
return
}
}
}()
log.Info("Started")
return nil
}
// Stop - Will stop the Cluster and release VIP if needed
func (cluster *Cluster) Stop() {
// Close the stop chanel, which will shut down the VIP (if needed)
close(cluster.stop)
// Wait until the completed channel is closed, signallign all shutdown tasks completed
<-cluster.completed
log.Info("Stopped")
}

381
pkg/cluster/service.go Normal file
View File

@@ -0,0 +1,381 @@
package cluster
import (
"context"
"errors"
"fmt"
"io/fs"
"net"
"os"
"os/signal"
"sync"
"syscall"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/arp"
"github.com/kube-vip/kube-vip/pkg/backend"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/loadbalancer"
"github.com/kube-vip/kube-vip/pkg/vip"
"github.com/vishvananda/netlink"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Config, sm *Manager, bgpServer *bgp.Server, cancelLeaderElection context.CancelFunc) error {
var err error
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
signalChan := make(chan os.Signal, 1)
// Add Notification for Userland interrupt
signal.Notify(signalChan, syscall.SIGINT)
// Add Notification for SIGTERM (sent from Kubernetes)
signal.Notify(signalChan, syscall.SIGTERM)
loadbalancers := []*loadbalancer.IPVSLoadBalancer{}
var arpWG sync.WaitGroup
for i := range cluster.Network {
network := cluster.Network[i]
if err := network.SetMask(c.VIPSubnet); err != nil {
log.Error("failed to set mask", "subnet", c.VIPSubnet, "err", err)
panic("")
}
if network.IsDDNS() {
if err := cluster.StartDDNS(ctxDNS); err != nil {
log.Error(err.Error())
}
}
// start the dns updater if address is dns
if network.IsDNS() {
log.Info("starting the DNS updater", "address", network.DNSName())
ipUpdater := vip.NewIPUpdater(network)
ipUpdater.Run(ctxDNS)
}
if !c.EnableRoutingTable {
if _, err = network.AddIP(false); err != nil {
log.Error(err.Error())
}
}
if c.EnableBGP {
// Lets advertise the VIP over BGP, the host needs to be passed using CIDR notation
log.Debug("Attempting to advertise over BGP", "address", network.CIDR())
err = bgpServer.AddHost(network.CIDR())
if err != nil {
log.Error(err.Error())
}
}
if c.EnableLoadBalancer {
lb, err := loadbalancer.NewIPVSLB(network.IP(), c.LoadBalancerPort, c.LoadBalancerForwardingMethod, c.BackendHealthCheckInterval, c.Interface, cancelLeaderElection, signalChan)
if err != nil {
log.Error("Error creating IPVS LoadBalancer", "err", err)
}
go func() {
err = sm.NodeWatcher(ctxArp, lb, c.Port) //TODO: We're using the ctxARP as the context this will change when rkatz finishes his change
if err != nil {
log.Error("Error watching node labels", "err", err)
}
}()
loadbalancers = append(loadbalancers, lb)
}
if c.EnableARP {
arpWG.Add(1)
go cluster.layer2Update(ctxArp, network, c, &arpWG)
}
}
if c.EnableLoadBalancer {
// Shutdown function that will wait on this signal, unless we call it ourselves
<-signalChan
for _, lb := range loadbalancers {
err = lb.RemoveIPVSLB()
if err != nil {
log.Error("Error stopping IPVS LoadBalancer", "err", err)
}
}
}
if c.EnableRoutingTable {
backendMapV4 := backend.Map{}
backendMapV6 := backend.Map{}
// only check localhost
nodename := ""
if c.NodeName != "" {
nodename = c.NodeName
} else {
nodename = os.Getenv("HOSTNAME")
}
ips := []string{}
if nodename != "" {
if ips, err = getNodeIPs(ctxArp, nodename, sm.KubernetesClient); err != nil && !apierrors.IsNotFound(err) {
log.Error("failed to get IP of control-plane nod", "err", err)
}
}
if len(ips) == 0 {
isV6, err := isV6(cluster.Network[0].IP())
if err != nil {
return fmt.Errorf("failed to parse IP '%s'", cluster.Network[0].IP())
}
if !isV6 {
ips = append(ips, "127.0.0.1")
} else {
ips = append(ips, "::1")
}
log.Info("no IP address found for node - will fallback to use localhost address", "addresses", ips)
}
for _, ip := range ips {
entry := backend.Entry{Addr: ip, Port: c.Port}
ipv6, err := isV6(ip)
if err != nil {
log.Error("failed to check IP type", "IP", ip, "error", err)
}
if !ipv6 {
backendMapV4[entry] = false
} else {
backendMapV6[entry] = false
}
}
stop := make(chan struct{})
// will wait for system interrupt and will send stop signal to backend watch
go func() {
<-signalChan
stop <- struct{}{}
}()
backend.Watch(func() {
for i := range cluster.Network {
network := cluster.Network[i]
networkIP := network.IP()
isNetworkV6, err := isV6(networkIP)
if err != nil {
log.Error("failed to check IP type", "IP", networkIP, "error", err)
continue
}
backendMap := &backendMapV4
if isNetworkV6 {
backendMap = &backendMapV6
}
for entry := range *backendMap {
if entry.Check() {
_, err = network.AddIP(true)
if err != nil {
log.Error("error adding address", "err", err)
}
if !(*backendMap)[entry] {
log.Info("added backend", "ip", network.IP())
}
err = network.AddRoute(true)
if err != nil && !errors.Is(err, fs.ErrExist) && !errors.Is(err, syscall.ESRCH) {
log.Warn(err.Error())
} else if err == nil && !(*backendMap)[entry] {
log.Info("added route", "route", network.PrepareRoute().String())
}
(*backendMap)[entry] = true
break
}
(*backendMap)[entry] = false
}
deleteAddress := true
for entry := range *backendMap {
if (*backendMap)[entry] {
deleteAddress = false
break
}
}
if deleteAddress {
err = network.DeleteRoute()
if err != nil && !errors.Is(err, fs.ErrNotExist) && !errors.Is(err, syscall.ESRCH) {
log.Warn("deleting route", "err", err)
} else if err == nil {
log.Info("deleted route", "route", network.PrepareRoute().String())
}
deleted, err := network.DeleteIP()
if err != nil {
log.Error("error deleting IP", "err", err)
panic("")
}
if deleted {
log.Info("deleted address", "IP", network.IP(), "interface", network.Interface())
}
}
}
}, c.BackendHealthCheckInterval, stop)
}
return nil
}
func isV6(ip string) (bool, error) {
ipaddr := net.ParseIP(ip)
if ipaddr == nil {
return false, fmt.Errorf("failed to parse IP '%s'", ip)
}
return ipaddr.To4() == nil, nil
}
func getNodeIPs(ctx context.Context, nodename string, client *kubernetes.Clientset) ([]string, error) {
node, err := client.CoreV1().Nodes().Get(ctx, nodename, metav1.GetOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return []string{}, fmt.Errorf("failed to get data about '%s' node: %w", nodename, err)
}
ips := []string{}
for _, addr := range node.Status.Addresses {
if addr.Type == corev1.NodeInternalIP {
ips = append(ips, addr.Address)
}
}
return ips, nil
}
// StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle
func (cluster *Cluster) StartLoadBalancerService(ctx context.Context, c *kubevip.Config, bgp *bgp.Server, name string, CountRouteReferences func(*netlink.Route) int) {
// use a Go context so we can tell the arp loop code when we
// want to step down
//nolint
ctxArp, cancelArp := context.WithCancel(ctx)
cluster.stop = make(chan bool, 1)
cluster.completed = make(chan bool, 1)
var arpWG sync.WaitGroup
for i := range cluster.Network {
network := cluster.Network[i]
if err := network.SetMask(c.VIPSubnet); err != nil {
log.Error("failed to set mask", "subnet", c.VIPSubnet, "err", err)
panic("")
}
_, err := network.DeleteIP()
if err != nil {
log.Warn("attempted to clean existing VIP", "err", err)
}
if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) {
err = network.AddRoute(false)
if err != nil {
log.Warn(err.Error())
}
} else if !c.EnableRoutingTable {
if _, err = network.AddIP(false); err != nil {
log.Warn(err.Error())
}
}
if c.EnableARP {
arpWG.Add(1)
go cluster.layer2Update(ctxArp, network, c, &arpWG)
}
if c.EnableBGP && (c.EnableLeaderElection || c.EnableServicesElection) {
// Lets advertise the VIP over BGP, the host needs to be passed using CIDR notation
log.Debug("(svcs) attempting to advertise over BGP", "address", network.CIDR())
err = bgp.AddHost(network.CIDR())
if err != nil {
log.Error(err.Error())
}
}
}
go func() {
<-cluster.stop
// Stop the Arp context if it is running
cancelArp()
arpWG.Wait() // wait for all cluster ARP/NDP to be finished
log.Info("[LOADBALANCER] Stopping load balancers", "name", name)
if c.EnableRoutingTable {
for i := range cluster.Network {
// chek if route is not referenced by another service
r := cluster.Network[i].PrepareRoute()
if CountRouteReferences(r) < 1 {
log.Info("[VIP] Deleting Route for VIP", "IP", cluster.Network[i].IP())
if err := cluster.Network[i].DeleteRoute(); err != nil {
log.Warn(err.Error())
}
}
}
close(cluster.completed)
return
}
for i := range cluster.Network {
if c.EnableARP && cluster.arpMgr.Count(cluster.Network[i].ARPName()) > 0 {
continue
}
log.Info("[VIP] Deleting VIP", "ip", cluster.Network[i].IP())
deleted, err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warn(err.Error())
}
if deleted {
log.Info("deleted address", "IP", cluster.Network[i].IP(), "interface", cluster.Network[i].Interface())
}
}
close(cluster.completed)
}()
}
// Layer2Update, handles the creation of the
func (cluster *Cluster) layer2Update(ctx context.Context, network vip.Network, c *kubevip.Config, arpWG *sync.WaitGroup) {
defer arpWG.Done()
log.Info("layer 2 broadcaster starting")
var ndp *vip.NdpResponder
var err error
ipString := network.IP()
if vip.IsIPv6(ipString) {
if network.IPisLinkLocal() {
log.Error("layer2 is link-local can't use NDP", "address", ipString)
} else {
ndp, err = vip.NewNDPResponder(network.Interface())
if err != nil {
log.Error("failed to create new NDP Responder", "error", err)
} else {
if ndp != nil {
defer ndp.Close()
}
}
}
}
log.Debug("layer 2 update", "ip", ipString, "interface", network.Interface(), "ms", c.ArpBroadcastRate)
arpInstance := arp.NewInstance(network, ndp)
cluster.arpMgr.Insert(arpInstance)
<-ctx.Done() // if cancel() execute
log.Debug("ending layer 2 update", "ip", ipString, "interface", network.Interface(), "ms", c.ArpBroadcastRate)
cluster.arpMgr.Remove(arpInstance)
}

View File

@@ -1,103 +1,84 @@
package cluster
import (
log "github.com/sirupsen/logrus"
"context"
"github.com/plunder-app/kube-vip/pkg/kubevip"
"github.com/plunder-app/kube-vip/pkg/loadbalancer"
"github.com/plunder-app/kube-vip/pkg/vip"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/vip"
)
// StartSingleNode will start a single node cluster
func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) error {
// Start kube-vip as a single node server
// TODO - Split all this code out as a seperate function
log.Infoln("Starting kube-vip as a single node cluster")
// TODO - Split all this code out as a separate function
log.Info("Starting kube-vip as a single node cluster")
log.Info("This node is assuming leadership of the cluster")
cluster.stop = make(chan bool, 1)
cluster.completed = make(chan bool, 1)
// Managers for Vip load balancers and none-vip loadbalancers
nonVipLB := loadbalancer.LBManager{}
VipLB := loadbalancer.LBManager{}
// Iterate through all Configurations
for x := range c.LoadBalancers {
// If the load balancer doesn't bind to the VIP
if c.LoadBalancers[x].BindToVip == false {
err := nonVipLB.Add("", &c.LoadBalancers[x])
for i := range cluster.Network {
if !disableVIP {
deleted, err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
log.Warn("Attempted to clean existing VIP", "err", err)
}
if deleted {
log.Info("deleted address", "IP", cluster.Network[i].IP(), "interface", cluster.Network[i].Interface())
}
_, err = cluster.Network[i].AddIP(false)
if err != nil {
log.Warn(err.Error())
}
}
}
if !disableVIP {
err := cluster.network.DeleteIP()
if err != nil {
log.Warnf("Attempted to clean existing VIP => %v", err)
}
err = cluster.network.AddIP()
if err != nil {
log.Warnf("%v", err)
}
// Once we have the VIP running, start the load balancer(s) that bind to the VIP
for x := range c.LoadBalancers {
if c.LoadBalancers[x].BindToVip == true {
err = VipLB.Add(c.VIP, &c.LoadBalancers[x])
if err != nil {
log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err)
}
if c.EnableARP {
// Gratuitous ARP, will broadcast to new MAC <-> IP
err := vip.ARPSendGratuitous(cluster.Network[i].IP(), c.Interface)
if err != nil {
log.Warn(err.Error())
}
}
}
if c.GratuitousARP == true {
// Gratuitous ARP, will broadcast to new MAC <-> IP
err := vip.ARPSendGratuitous(c.VIP, c.Interface)
if err != nil {
log.Warnf("%v", err)
}
}
go func() {
for {
select {
case <-cluster.stop:
log.Info("[LOADBALANCER] Stopping load balancers")
<-cluster.stop
// Stop all load balancers associated with the VIP
err := VipLB.StopAll()
if !disableVIP {
for i := range cluster.Network {
log.Info("[VIP] Releasing the VIP", "address", cluster.Network[i].IP())
deleted, err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
// Stop all load balancers associated with the Host
err = nonVipLB.StopAll()
if err != nil {
log.Warnf("%v", err)
if deleted {
log.Info("deleted address", "IP", cluster.Network[i].IP(), "interface", cluster.Network[i].Interface())
}
if !disableVIP {
log.Info("[VIP] Releasing the Virtual IP")
err = cluster.network.DeleteIP()
if err != nil {
log.Warnf("%v", err)
}
}
close(cluster.completed)
return
}
}
close(cluster.completed)
}()
log.Infoln("Started Load Balancer and Virtual IP")
log.Info("Started Load Balancer and Virtual IP")
return nil
}
func (cluster *Cluster) StartVipService(c *kubevip.Config, sm *Manager, bgp *bgp.Server) error {
// use a Go context so we can tell the arp loop code when we
// want to step down
ctxArp, cancelArp := context.WithCancel(context.Background())
defer cancelArp()
// use a Go context so we can tell the dns loop code when we
// want to step down
ctxDNS, cancelDNS := context.WithCancel(context.Background())
defer cancelDNS()
return cluster.vipService(ctxArp, ctxDNS, c, sm, bgp, nil)
}

View File

@@ -1,39 +0,0 @@
package cluster
import (
"io"
"github.com/hashicorp/raft"
)
// FSM - Finite State Machine for Raft
type FSM struct {
}
// Apply - TODO
func (fsm FSM) Apply(log *raft.Log) interface{} {
return nil
}
// Restore - TODO
func (fsm FSM) Restore(snap io.ReadCloser) error {
return nil
}
// Snapshot - TODO, returns an empty snapshot
func (fsm FSM) Snapshot() (raft.FSMSnapshot, error) {
return Snapshot{}, nil
}
// Snapshot -
type Snapshot struct {
}
// Persist -
func (snapshot Snapshot) Persist(sink raft.SnapshotSink) error {
return nil
}
// Release -
func (snapshot Snapshot) Release() {
}

View File

@@ -22,7 +22,7 @@ func FindIPAddress(addrName string) (string, string, error) {
}
for _, a := range addrs {
if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
if ipnet.IP.To16() != nil {
address = ipnet.IP.String()
// If we're not searching for a specific adapter return the first one
if addrName == "" {

99
pkg/egress/egress.go Normal file
View File

@@ -0,0 +1,99 @@
package egress
import (
"fmt"
"strings"
"github.com/kube-vip/kube-vip/pkg/iptables"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/nftables"
"github.com/kube-vip/kube-vip/pkg/vip"
)
func Teardown(podIP, vipIP, namespace, serviceUUID string, annotations map[string]string, useNftables bool) error {
// Look up the destination ports from the annotations on the service
destinationPorts := annotations[kubevip.EgressDestinationPorts]
deniedNetworks := annotations[kubevip.EgressDeniedNetworks]
allowedNetworks := annotations[kubevip.EgressAllowedNetworks]
internalEgress := annotations[kubevip.EgressInternal]
protocol := iptables.ProtocolIPv4
IPv6 := false
if vip.IsIPv6(podIP) {
protocol = iptables.ProtocolIPv6
IPv6 = true
}
// Use the internal egress implementation
if internalEgress != "" {
return nftables.DeleteSNAT(IPv6, serviceUUID)
}
i, err := vip.CreateIptablesClient(useNftables, namespace, protocol)
if err != nil {
return fmt.Errorf("error Creating iptables client [%s]", err)
}
if deniedNetworks != "" {
networks := strings.Split(deniedNetworks, ",")
for x := range networks {
err = i.DeleteMangleReturnForNetwork(vip.MangleChainName, networks[x])
if err != nil {
return fmt.Errorf("error deleting rules in mangle chain [%s], error [%s]", vip.MangleChainName, err)
}
}
}
if allowedNetworks != "" {
networks := strings.Split(allowedNetworks, ",")
for x := range networks {
err = i.DeleteMangleMarkingForNetwork(podIP, vip.MangleChainName, networks[x])
if err != nil {
return fmt.Errorf("error deleting rules in mangle chain [%s], error [%s]", vip.MangleChainName, err)
}
}
} else {
// Remove the marking of egress packets
err = i.DeleteMangleMarking(podIP, vip.MangleChainName)
if err != nil {
return fmt.Errorf("error changing iptables rules for egress [%s]", err)
}
}
// Clear up SNAT rules
if destinationPorts != "" {
fixedPorts := strings.Split(destinationPorts, ",")
for _, fixedPort := range fixedPorts {
var proto, port string
data := strings.Split(fixedPort, ":")
if len(data) == 0 {
continue
} else if len(data) == 1 {
proto = "tcp"
port = data[0]
} else {
proto = data[0]
port = data[1]
}
err = i.DeleteSourceNatForDestinationPort(podIP, vipIP, port, proto)
if err != nil {
return fmt.Errorf("error changing iptables rules for egress [%s]", err)
}
}
} else {
err = i.DeleteSourceNat(podIP, vipIP)
if err != nil {
return fmt.Errorf("error changing iptables rules for egress [%s]", err)
}
}
err = vip.DeleteExistingSessions(podIP, false, destinationPorts, "")
if err != nil {
return fmt.Errorf("error changing iptables rules for egress [%s]", err)
}
return nil
}

165
pkg/endpoints/endpoints.go Normal file
View File

@@ -0,0 +1,165 @@
package endpoints
import (
"context"
"fmt"
"net"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/endpoints/providers"
"github.com/kube-vip/kube-vip/pkg/instance"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/servicecontext"
v1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
"k8s.io/apimachinery/pkg/watch"
)
type Processor struct {
config *kubevip.Config
provider providers.Provider
bgpServer *bgp.Server
worker endpointWorker
instances *[]*instance.Instance
}
func NewEndpointProcessor(config *kubevip.Config, provider providers.Provider, bgpServer *bgp.Server,
instances *[]*instance.Instance) *Processor {
return &Processor{
config: config,
provider: provider,
bgpServer: bgpServer,
instances: instances,
worker: newEndpointWorker(config, provider, bgpServer, instances),
}
}
func (p *Processor) AddOrModify(ctx *servicecontext.Context, event watch.Event,
lastKnownGoodEndpoint *string, service *v1.Service, id string, leaderElectionActive *bool,
serviceFunc func(context.Context, *v1.Service) error,
leaderCtx *context.Context, cancel *context.CancelFunc) (bool, error) {
var err error
if err = p.provider.LoadObject(event.Object, *cancel); err != nil {
return false, fmt.Errorf("[%s] error loading k8s object: %w", p.provider.GetLabel(), err)
}
endpoints, err := p.worker.getEndpoints(service, id)
if err != nil {
return false, err
}
if err := p.worker.setInstanceEndpointsStatus(service, endpoints); err != nil {
log.Error("updating instance", "err", err)
}
// Find out if we have any local endpoints
// if out endpoint is empty then populate it
// if not, go through the endpoints and see if ours still exists
// If we have a local endpoint then begin the leader Election, unless it's already running
//
// Check that we have local endpoints
if len(endpoints) != 0 {
// Ignore IPv4
if service.Annotations[kubevip.EgressIPv6] == "true" && net.ParseIP(endpoints[0]).To4() != nil {
return true, nil
}
p.updateLastKnownGoodEndpoint(lastKnownGoodEndpoint, endpoints, service, leaderElectionActive, *cancel)
// start leader election if it's enabled and not already started
if !*leaderElectionActive && p.config.EnableServicesElection {
go func() {
*leaderCtx, *cancel = context.WithCancel(ctx.Ctx)
startLeaderElection(*leaderCtx, leaderElectionActive, service, serviceFunc)
}()
}
// There are local endpoints available on the node
if !p.config.EnableServicesElection && !p.config.EnableLeaderElection {
if err := p.worker.processInstance(ctx, service, leaderElectionActive); err != nil {
return false, fmt.Errorf("failed to process non-empty instance: %w", err)
}
}
} else {
// There are no local endpoints
p.worker.clear(ctx, lastKnownGoodEndpoint, service, *cancel, leaderElectionActive)
}
// Set the service accordingly
p.updateAnnotations(service, lastKnownGoodEndpoint)
log.Debug("watcher", "provider",
p.provider.GetLabel(), "service name", service.Name, "namespace", service.Namespace, "endpoints", len(endpoints), "last endpoint", *lastKnownGoodEndpoint, "active leader election", *leaderElectionActive)
return false, nil
}
func (p *Processor) Delete(service *v1.Service, id string) error {
if err := p.worker.delete(service, id); err != nil {
return fmt.Errorf("[%s] error deleting service: %w", p.provider.GetLabel(), err)
}
return nil
}
func (p *Processor) updateLastKnownGoodEndpoint(lastKnownGoodEndpoint *string, endpoints []string, service *v1.Service, leaderElectionActive *bool, cancel context.CancelFunc) {
// if we haven't populated one, then do so
if *lastKnownGoodEndpoint == "" {
*lastKnownGoodEndpoint = endpoints[0]
return
}
// check out previous endpoint exists
stillExists := false
for x := range endpoints {
if endpoints[x] == *lastKnownGoodEndpoint {
stillExists = true
}
}
// If the last endpoint no longer exists, we cancel our leader Election, and set another endpoint as last known good
if !stillExists {
p.worker.removeEgress(service, lastKnownGoodEndpoint)
if *leaderElectionActive && (p.config.EnableServicesElection || p.config.EnableLeaderElection) {
log.Warn("existing endpoint has been removed, restarting leaderElection", "provider", p.provider.GetLabel(), "endpoint", *lastKnownGoodEndpoint)
// Stop the existing leaderElection
cancel()
// disable last leaderElection flag
*leaderElectionActive = false
}
// Set our active endpoint to an existing one
*lastKnownGoodEndpoint = endpoints[0]
}
}
func (p *Processor) updateAnnotations(service *v1.Service, lastKnownGoodEndpoint *string) {
// Set the service accordingly
if service.Annotations[kubevip.Egress] == "true" {
activeEndpointAnnotation := kubevip.ActiveEndpoint
if !p.config.EnableEndpoints && p.provider.GetProtocol() == string(discoveryv1.AddressTypeIPv6) {
activeEndpointAnnotation = kubevip.ActiveEndpointIPv6
}
service.Annotations[activeEndpointAnnotation] = *lastKnownGoodEndpoint
}
}
func startLeaderElection(ctx context.Context, leaderElectionActive *bool, service *v1.Service, serviceFunc func(context.Context, *v1.Service) error) {
// This is a blocking function, that will restart (in the event of failure)
for {
// if the context isn't cancelled restart
if ctx.Err() != context.Canceled {
*leaderElectionActive = true
err := serviceFunc(ctx, service)
if err != nil {
log.Error(err.Error())
}
*leaderElectionActive = false
} else {
*leaderElectionActive = false
break
}
}
}

View File

@@ -0,0 +1,125 @@
package endpoints
import (
"context"
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/instance"
"github.com/kube-vip/kube-vip/pkg/servicecontext"
v1 "k8s.io/api/core/v1"
)
type BGP struct {
generic
bgpServer *bgp.Server
}
func newBGP(generic generic, bgpServer *bgp.Server) endpointWorker {
return &BGP{
generic: generic,
bgpServer: bgpServer,
}
}
func (b *BGP) processInstance(ctx *servicecontext.Context, service *v1.Service, leaderElectionActive *bool) error {
if instance := instance.FindServiceInstance(service, *b.instances); instance != nil {
for _, cluster := range instance.Clusters {
for i := range cluster.Network {
if !ctx.IsNetworkConfigured(cluster.Network[i].IP()) {
log.Debug("attempting to advertise BGP service", "provider", b.provider.GetLabel(), "ip", cluster.Network[i].IP())
err := b.bgpServer.AddHost(cluster.Network[i].CIDR())
if err != nil {
log.Error("error adding BGP host", "provider", b.provider.GetLabel(), "err", err)
} else {
log.Info("added BGP host", "provider",
b.provider.GetLabel(), "ip", cluster.Network[i].CIDR(), "service name", service.Name, "namespace", service.Namespace)
ctx.ConfiguredNetworks.Store(cluster.Network[i].IP(), true)
*leaderElectionActive = true
}
}
}
}
}
return nil
}
func (b *BGP) clear(ctx *servicecontext.Context, lastKnownGoodEndpoint *string, service *v1.Service, cancel context.CancelFunc, leaderElectionActive *bool) {
if !b.config.EnableServicesElection && !b.config.EnableLeaderElection {
// If BGP mode is enabled - routes should be deleted
if instance := instance.FindServiceInstance(service, *b.instances); instance != nil {
for _, cluster := range instance.Clusters {
for i := range cluster.Network {
err := b.bgpServer.DelHost(cluster.Network[i].CIDR())
if err != nil {
log.Error("deleting BGP host", "provider", b.provider.GetLabel(), "ip", cluster.Network[i].IP(), "err", err)
} else {
log.Info("deleted BGP host", "provider",
b.provider.GetLabel(), "ip", cluster.Network[i].IP(), "service name", service.Name, "namespace", service.Namespace)
ctx.ConfiguredNetworks.Delete(cluster.Network[i])
*leaderElectionActive = false
}
}
}
}
}
b.clearEgress(lastKnownGoodEndpoint, service, cancel, leaderElectionActive)
}
func (b *BGP) getEndpoints(service *v1.Service, id string) ([]string, error) {
return b.getAllEndpoints(service, id)
}
func (b *BGP) delete(service *v1.Service, id string) error {
// When no-leader-elecition mode
if !b.config.EnableServicesElection && !b.config.EnableLeaderElection {
// find all existing local endpoints
endpoints, err := b.getEndpoints(service, id)
if err != nil {
return fmt.Errorf("[%s] error getting endpoints: %w", b.provider.GetLabel(), err)
}
// If there were local endpoints deleted
if len(endpoints) > 0 {
b.deleteAction(service)
}
}
return nil
}
func (b *BGP) deleteAction(service *v1.Service) {
b.clearBGPHosts(service)
}
func (b *BGP) clearBGPHosts(service *v1.Service) {
ClearBGPHosts(service, b.instances, b.bgpServer)
}
func (b *BGP) setInstanceEndpointsStatus(_ *v1.Service, _ []string) error {
return nil
}
func ClearBGPHosts(service *v1.Service, instances *[]*instance.Instance, bgpServer *bgp.Server) {
if instance := instance.FindServiceInstance(service, *instances); instance != nil {
ClearBGPHostsByInstance(instance, bgpServer)
}
}
func ClearBGPHostsByInstance(instance *instance.Instance, bgpServer *bgp.Server) {
for _, cluster := range instance.Clusters {
for i := range cluster.Network {
network := cluster.Network[i]
err := bgpServer.DelHost(network.CIDR())
if err != nil {
log.Error("[endpoint] error deleting BGP host", "err", err)
} else {
log.Debug("[endpoint] deleted BGP host", "ip",
network.CIDR(), "service name", instance.ServiceSnapshot.Name, "namespace", instance.ServiceSnapshot.Namespace)
}
}
}
}

View File

@@ -0,0 +1,118 @@
package endpoints
import (
"context"
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/egress"
"github.com/kube-vip/kube-vip/pkg/endpoints/providers"
"github.com/kube-vip/kube-vip/pkg/instance"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/servicecontext"
v1 "k8s.io/api/core/v1"
)
type endpointWorker interface {
processInstance(svcCtx *servicecontext.Context, service *v1.Service, leaderElectionActive *bool) error
clear(svcCtx *servicecontext.Context, lastKnownGoodEndpoint *string, service *v1.Service, cancel context.CancelFunc, leaderElectionActive *bool)
getEndpoints(service *v1.Service, id string) ([]string, error)
removeEgress(service *v1.Service, lastKnownGoodEndpoint *string)
delete(service *v1.Service, id string) error
setInstanceEndpointsStatus(service *v1.Service, endpoints []string) error
}
func newEndpointWorker(config *kubevip.Config, provider providers.Provider, bgpServer *bgp.Server, instances *[]*instance.Instance) endpointWorker {
generic := newGeneric(config, provider, instances)
if config.EnableRoutingTable {
return newRoutingTable(generic)
}
if config.EnableBGP {
return newBGP(generic, bgpServer)
}
return &generic
}
type generic struct {
config *kubevip.Config
provider providers.Provider
instances *[]*instance.Instance
}
func newGeneric(config *kubevip.Config, provider providers.Provider, instances *[]*instance.Instance) generic {
return generic{
config: config,
provider: provider,
instances: instances,
}
}
func (g *generic) processInstance(_ *servicecontext.Context, _ *v1.Service, _ *bool) error {
return nil
}
func (g *generic) clear(_ *servicecontext.Context, lastKnownGoodEndpoint *string, service *v1.Service, cancel context.CancelFunc, leaderElectionActive *bool) {
g.clearEgress(lastKnownGoodEndpoint, service, cancel, leaderElectionActive)
}
func (g *generic) clearEgress(lastKnownGoodEndpoint *string, service *v1.Service, cancel context.CancelFunc, leaderElectionActive *bool) {
if *lastKnownGoodEndpoint != "" {
log.Warn("existing endpoint has been removed, no remaining endpoints for leaderElection", "provider", g.provider.GetLabel(), "endpoint", lastKnownGoodEndpoint)
if err := egress.Teardown(*lastKnownGoodEndpoint, service.Spec.LoadBalancerIP, service.Namespace, string(service.UID), service.Annotations, g.config.EgressWithNftables); err != nil {
log.Error("error removing redundant egress rules", "err", err)
}
*lastKnownGoodEndpoint = "" // reset endpoint
if g.config.EnableServicesElection || g.config.EnableLeaderElection {
cancel() // stop services watcher
}
*leaderElectionActive = false
}
}
func (g *generic) getEndpoints(_ *v1.Service, id string) ([]string, error) {
return g.getLocalEndpoints(id)
}
func (g *generic) getLocalEndpoints(id string) ([]string, error) {
// Build endpoints
var endpoints []string
var err error
if endpoints, err = g.provider.GetLocalEndpoints(id, g.config); err != nil {
return nil, fmt.Errorf("[%s] error getting local endpoints: %w", g.provider.GetLabel(), err)
}
return endpoints, nil
}
func (g *generic) getAllEndpoints(service *v1.Service, id string) ([]string, error) {
// Build endpoints
var err error
var endpoints []string
if !g.config.EnableLeaderElection && !g.config.EnableServicesElection &&
service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeCluster {
if endpoints, err = g.provider.GetAllEndpoints(); err != nil {
return nil, fmt.Errorf("[%s] error getting all endpoints: %w", g.provider.GetLabel(), err)
}
} else {
if endpoints, err = g.provider.GetLocalEndpoints(id, g.config); err != nil {
return nil, fmt.Errorf("[%s] error getting local endpoints: %w", g.provider.GetLabel(), err)
}
}
return endpoints, nil
}
func (g *generic) removeEgress(_ *v1.Service, _ *string) {
}
func (g *generic) delete(_ *v1.Service, _ string) error {
return nil
}
func (g *generic) setInstanceEndpointsStatus(_ *v1.Service, _ []string) error {
return nil
}

View File

@@ -0,0 +1,178 @@
package endpoints
import (
"context"
"errors"
"fmt"
"net"
"syscall"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/egress"
"github.com/kube-vip/kube-vip/pkg/instance"
"github.com/kube-vip/kube-vip/pkg/servicecontext"
"github.com/vishvananda/netlink"
v1 "k8s.io/api/core/v1"
)
type RoutingTable struct {
generic
}
func newRoutingTable(generic generic) endpointWorker {
return &RoutingTable{
generic: generic,
}
}
func (rt *RoutingTable) processInstance(ctx *servicecontext.Context, service *v1.Service, leaderElectionActive *bool) error {
instance := instance.FindServiceInstance(service, *rt.instances)
if instance != nil {
for _, cluster := range instance.Clusters {
for i := range cluster.Network {
if !ctx.IsNetworkConfigured(cluster.Network[i].IP()) && cluster.Network[i].HasEndpoints() {
err := cluster.Network[i].AddRoute(false)
if err != nil {
if errors.Is(err, syscall.EEXIST) {
// If route exists, but protocol is not set (e.g. the route was created by the older version
// of kube-vip) try to update it if necessary
isUpdated, err := cluster.Network[i].UpdateRoutes()
if err != nil {
return fmt.Errorf("[%s] error updating existing routes: %w", rt.provider.GetLabel(), err)
}
if isUpdated {
log.Info("updated route", "provider",
rt.provider.GetLabel(), "ip", cluster.Network[i].IP(), "service name", service.Name, "namespace",
service.Namespace, "interface", cluster.Network[i].Interface(), "tableID", rt.config.RoutingTableID)
} else {
log.Info("route already present", "provider",
rt.provider.GetLabel(), "ip", cluster.Network[i].IP(), "service name", service.Name, "namespace",
service.Namespace, "interface", cluster.Network[i].Interface(), "tableID", rt.config.RoutingTableID)
}
} else {
// If other error occurs, return error
return fmt.Errorf("[%s] error adding route: %s", rt.provider.GetLabel(), err.Error())
}
} else {
log.Info("added route", "provider",
rt.provider.GetLabel(), "ip", cluster.Network[i].IP(), "service name", service.Name, "namespace",
service.Namespace, "interface", cluster.Network[i].Interface(), "tableID", rt.config.RoutingTableID)
ctx.ConfiguredNetworks.Store(cluster.Network[i].IP(), true)
*leaderElectionActive = true
}
}
}
}
}
return nil
}
func (rt *RoutingTable) clear(svcCtx *servicecontext.Context, lastKnownGoodEndpoint *string, service *v1.Service, cancel context.CancelFunc, leaderElectionActive *bool) {
if !rt.config.EnableServicesElection && !rt.config.EnableLeaderElection {
if errs := ClearRoutes(service, rt.instances); len(errs) == 0 {
svcCtx.ConfiguredNetworks.Clear()
} else {
for _, err := range errs {
log.Error("error while clearing routes", "err", err)
}
}
}
rt.clearEgress(lastKnownGoodEndpoint, service, cancel, leaderElectionActive)
}
func (rt *RoutingTable) getEndpoints(service *v1.Service, id string) ([]string, error) {
return rt.getAllEndpoints(service, id)
}
func (rt *RoutingTable) removeEgress(service *v1.Service, lastKnownGoodEndpoint *string) {
if err := egress.Teardown(*lastKnownGoodEndpoint, service.Spec.LoadBalancerIP,
service.Namespace, string(service.UID), service.Annotations, rt.config.EgressWithNftables); err != nil {
log.Warn("removing redundant egress rules", "err", err)
}
}
func (rt *RoutingTable) delete(service *v1.Service, id string) error {
// When no-leader-elecition mode
if !rt.config.EnableServicesElection && !rt.config.EnableLeaderElection {
// find all existing local endpoints
endpoints, err := rt.getEndpoints(service, id)
if err != nil {
return fmt.Errorf("[%s] error getting endpoints: %w", rt.provider.GetLabel(), err)
}
// If there were local endpoints deleted
if len(endpoints) > 0 {
rt.deleteAction(service)
}
}
return nil
}
func (rt *RoutingTable) deleteAction(service *v1.Service) {
ClearRoutes(service, rt.instances)
}
func (rt *RoutingTable) setInstanceEndpointsStatus(service *v1.Service, endpoints []string) error {
instance := instance.FindServiceInstance(service, *rt.instances)
if instance == nil {
log.Error("failed to find the instance", "service", service.UID, "provider", rt.provider.GetLabel())
} else {
for _, c := range instance.Clusters {
for n := range c.Network {
// if there are no endpoints set HasEndpoints false just in case
if len(endpoints) < 1 {
c.Network[n].SetHasEndpoints(false)
}
// check if endpoint are available and are of same IP family as service
if len(endpoints) > 0 && ((net.ParseIP(c.Network[n].IP()).To4() == nil) == (net.ParseIP(endpoints[0]).To4() == nil)) {
c.Network[n].SetHasEndpoints(true)
}
}
}
}
return nil
}
func ClearRoutes(service *v1.Service, instances *[]*instance.Instance) []error {
errs := []error{}
if instance := instance.FindServiceInstance(service, *instances); instance != nil {
for _, cluster := range instance.Clusters {
for i := range cluster.Network {
route := cluster.Network[i].PrepareRoute()
// check if route we are about to delete is not referenced by more than one service
if CountRouteReferences(route, instances) <= 1 {
err := cluster.Network[i].DeleteRoute()
if err != nil && !errors.Is(err, syscall.ESRCH) {
log.Error("failed to delete route", "ip", cluster.Network[i].IP(), "err", err)
errs = append(errs, err)
}
log.Debug("deleted route", "ip",
cluster.Network[i].IP(), "service name", service.Name, "namespace", service.Namespace, "interface", cluster.Network[i].Interface())
}
}
}
}
return errs
}
func CountRouteReferences(route *netlink.Route, instances *[]*instance.Instance) int {
cnt := 0
for _, instance := range *instances {
for _, cluster := range instance.Clusters {
for n := range cluster.Network {
if cluster.Network[n].HasEndpoints() {
r := cluster.Network[n].PrepareRoute()
if r.Dst.String() == route.Dst.String() {
cnt++
}
}
}
}
}
return cnt
}

View File

@@ -0,0 +1,137 @@
package providers
import (
"context"
"fmt"
"strings"
"github.com/kube-vip/kube-vip/pkg/kubevip"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/client-go/util/retry"
log "log/slog"
)
type Endpoints struct {
label string
//nolint:staticcheck // SA1019 endpoints are moving to an opt-in only
endpoints *v1.Endpoints
}
func NewEndpoints() Provider {
return &Endpoints{
label: "endpoints",
}
}
func (ep *Endpoints) CreateRetryWatcher(ctx context.Context, clientSet *kubernetes.Clientset,
service *v1.Service) (*watchtools.RetryWatcher, error) {
opts := metav1.ListOptions{
FieldSelector: fields.OneTermEqualSelector("metadata.name", service.Name).String(),
}
rw, err := watchtools.NewRetryWatcherWithContext(ctx, "1", &cache.ListWatch{
WatchFunc: func(_ metav1.ListOptions) (watch.Interface, error) {
return clientSet.CoreV1().Endpoints(service.Namespace).Watch(ctx, opts)
},
})
if err != nil {
return nil, fmt.Errorf("error creating endpoint watcher: %s", err.Error())
}
return rw, nil
}
func (ep *Endpoints) LoadObject(endpoints runtime.Object, cancel context.CancelFunc) error {
//nolint:staticcheck // SA1019 endpoints have to be explicitly requested now
eps, ok := endpoints.(*v1.Endpoints)
if !ok {
cancel()
return fmt.Errorf("[%s] unable to parse Kubernetes services from API watcher", ep.GetLabel())
}
ep.endpoints = eps
return nil
}
func (ep *Endpoints) GetAllEndpoints() ([]string, error) {
result := []string{}
for subset := range ep.endpoints.Subsets {
for address := range ep.endpoints.Subsets[subset].Addresses {
addr := strings.Split(ep.endpoints.Subsets[subset].Addresses[address].IP, "/")
result = append(result, addr[0])
}
}
return result, nil
}
func (ep *Endpoints) GetLocalEndpoints(id string, _ *kubevip.Config) ([]string, error) {
var localEndpoints []string
for _, subset := range ep.endpoints.Subsets {
for _, address := range subset.Addresses {
log.Debug("processing endpoint", "label", ep.label, "ip", address.IP)
// 1. Compare the Nodename
if address.NodeName != nil && id == *address.NodeName {
log.Debug("found local endpoint", "label", ep.label, "ip", address.IP, "hostname", address.Hostname, "nodename", *address.NodeName)
localEndpoints = append(localEndpoints, address.IP)
continue
}
// 2. Compare the Hostname (only useful if address.NodeName is not available)
if id == address.Hostname {
log.Debug("found local endpoint", "label", ep.label, "ip", address.IP, "hostname", address.Hostname)
localEndpoints = append(localEndpoints, address.IP)
continue
}
}
}
return localEndpoints, nil
}
func (ep *Endpoints) UpdateServiceAnnotation(endpoint string, _ string, service *v1.Service, clientSet *kubernetes.Clientset) error {
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
// Retrieve the latest version of Deployment before attempting update
// RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
currentService, err := clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{})
if err != nil {
return err
}
currentServiceCopy := currentService.DeepCopy()
if currentServiceCopy.Annotations == nil {
currentServiceCopy.Annotations = make(map[string]string)
}
currentServiceCopy.Annotations[kubevip.ActiveEndpoint] = endpoint
_, err = clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{})
if err != nil {
log.Error("error updating Service Spec", "label", ep.GetLabel(), "name", currentServiceCopy.Name, "err", err)
return err
}
return nil
})
if retryErr != nil {
log.Error("failed to set Services", "label", ep.GetLabel(), "err", retryErr)
return retryErr
}
return nil
}
func (ep *Endpoints) GetLabel() string {
return ep.label
}
func (ep *Endpoints) GetProtocol() string {
return ""
}

View File

@@ -0,0 +1,139 @@
package providers
import (
"context"
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
v1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/client-go/util/retry"
)
type Endpointslices struct {
label string
endpoints *discoveryv1.EndpointSlice
}
func NewEndpointslices() Provider {
return &Endpointslices{
label: "endpointslices",
}
}
func (ep *Endpointslices) CreateRetryWatcher(ctx context.Context, clientSet *kubernetes.Clientset,
service *v1.Service) (*watchtools.RetryWatcher, error) {
labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/service-name": service.Name}}
opts := metav1.ListOptions{
LabelSelector: labels.Set(labelSelector.MatchLabels).String(),
}
rw, err := watchtools.NewRetryWatcherWithContext(ctx, "1", &cache.ListWatch{
WatchFunc: func(_ metav1.ListOptions) (watch.Interface, error) {
return clientSet.DiscoveryV1().EndpointSlices(service.Namespace).Watch(ctx, opts)
},
})
if err != nil {
return nil, fmt.Errorf("[%s] error creating endpointslices watcher: %s", ep.label, err.Error())
}
return rw, nil
}
func (ep *Endpointslices) LoadObject(endpoints runtime.Object, cancel context.CancelFunc) error {
eps, ok := endpoints.(*discoveryv1.EndpointSlice)
if !ok {
cancel()
return fmt.Errorf("[%s] error casting endpoints to v1.Endpoints struct", ep.label)
}
ep.endpoints = eps
return nil
}
func (ep *Endpointslices) GetAllEndpoints() ([]string, error) {
result := []string{}
for _, ep := range ep.endpoints.Endpoints {
result = append(result, ep.Addresses...)
}
return result, nil
}
func (ep *Endpointslices) GetLocalEndpoints(id string, _ *kubevip.Config) ([]string, error) {
var localEndpoints []string
for _, endpoint := range ep.endpoints.Endpoints {
if !*endpoint.Conditions.Serving {
continue
}
for _, address := range endpoint.Addresses {
log.Debug("processing endpoint", "provider", ep.label, "ip", address)
// 1. Compare the Nodename
if endpoint.NodeName != nil && id == *endpoint.NodeName {
if endpoint.Hostname != nil {
log.Debug("found endpoint", "provider", ep.label, "ip", address, "hostname", *endpoint.Hostname, "nodename", *endpoint.NodeName)
} else {
log.Debug("found endpoint", "provider", ep.label, "ip", address, "nodename", *endpoint.NodeName)
}
localEndpoints = append(localEndpoints, address)
continue
}
// 2. Compare the Hostname (only useful if endpoint.NodeName is not available)
if endpoint.Hostname != nil && id == *endpoint.Hostname {
log.Debug("found endpoint", "provider", ep.label, "ip", address, "hostname", *endpoint.Hostname)
localEndpoints = append(localEndpoints, address)
}
}
}
return localEndpoints, nil
}
func (ep *Endpointslices) UpdateServiceAnnotation(endpoint, endpointIPv6 string, service *v1.Service, clientSet *kubernetes.Clientset) error {
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
// Retrieve the latest version of Deployment before attempting update
// RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
currentService, err := clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{})
if err != nil {
return err
}
currentServiceCopy := currentService.DeepCopy()
if currentServiceCopy.Annotations == nil {
currentServiceCopy.Annotations = make(map[string]string)
}
currentServiceCopy.Annotations[kubevip.ActiveEndpoint] = endpoint
currentServiceCopy.Annotations[kubevip.ActiveEndpointIPv6] = endpointIPv6
_, err = clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{})
if err != nil {
log.Error("error updating Service Spec", "provider", ep.label, "service name", currentServiceCopy.Name, "err", err)
return err
}
return nil
})
if retryErr != nil {
log.Error("failed to set Services", "provider", ep.label, "err", retryErr)
return retryErr
}
return nil
}
func (ep *Endpointslices) GetLabel() string {
return ep.label
}
func (ep *Endpointslices) GetProtocol() string {
return string(ep.endpoints.AddressType)
}

View File

@@ -0,0 +1,22 @@
package providers
import (
"context"
"github.com/kube-vip/kube-vip/pkg/kubevip"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
watchtools "k8s.io/client-go/tools/watch"
)
type Provider interface {
CreateRetryWatcher(context.Context, *kubernetes.Clientset,
*v1.Service) (*watchtools.RetryWatcher, error)
GetAllEndpoints() ([]string, error)
GetLocalEndpoints(string, *kubevip.Config) ([]string, error)
GetLabel() string
UpdateServiceAnnotation(string, string, *v1.Service, *kubernetes.Clientset) error
LoadObject(runtime.Object, context.CancelFunc) error
GetProtocol() string
}

26
pkg/etcd/client.go Normal file
View File

@@ -0,0 +1,26 @@
package etcd
import (
"go.etcd.io/etcd/client/pkg/v3/transport"
clientv3 "go.etcd.io/etcd/client/v3"
"github.com/kube-vip/kube-vip/pkg/kubevip"
)
func NewClient(c *kubevip.Config) (*clientv3.Client, error) {
tlsInfo := transport.TLSInfo{
TrustedCAFile: c.Etcd.CAFile,
CertFile: c.Etcd.ClientCertFile,
KeyFile: c.Etcd.ClientKeyFile,
}
clientTLS, err := tlsInfo.ClientConfig()
if err != nil {
return nil, err
}
return clientv3.New(clientv3.Config{
Endpoints: c.Etcd.Endpoints,
TLS: clientTLS,
})
}

227
pkg/etcd/election.go Normal file
View File

@@ -0,0 +1,227 @@
package etcd
import (
"context"
"hash/fnv"
"time"
log "log/slog"
"github.com/pkg/errors"
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/concurrency"
)
// LeaderElectionConfig allows to configure the leader election params.
type LeaderElectionConfig struct {
// EtcdConfig contains the client to connect to the etcd cluster.
EtcdConfig ClientConfig
// Name uniquely identifies this leader election. All members of the same election
// should use the same value here.
Name string
// MemberID identifies uniquely this contestant from other in the leader election.
// It will be converted to an int64 using a hash, so theoretically collisions are possible
// when using a string. If you want to guarantee safety, us MemberUniqueID to specify a unique
// int64 directly.
// If two processes start a leader election using the same MemberID, one of them will
// fail.
MemberID string
// MemberUniqueID is the int equivalent to MemberID that allows to override the default conversion
// from string to int using hashing.
MemberUniqueID *uint64
// LeaseDurationSeconds is the duration that non-leader candidates will
// wait to force acquire leadership.
// This is just a request to the etcd server but it's not guaranteed, the server
// might decide to make the duration longer.
LeaseDurationSeconds int64
// Callbacks are callbacks that are triggered during certain lifecycle
// events of the LeaderElector
Callbacks LeaderCallbacks
}
// LeaderCallbacks are callbacks that are triggered during certain
// lifecycle events of the election.
type LeaderCallbacks struct {
// OnStartedLeading is called when this member starts leading.
OnStartedLeading func(context.Context)
// OnStoppedLeading is called when this member stops leading.
OnStoppedLeading func()
// OnNewLeader is called when the client observes a leader that is
// not the previously observed leader. This includes the first observed
// leader when the client starts.
OnNewLeader func(identity string)
}
// ClientConfig contains the client to connect to the etcd cluster.
type ClientConfig struct {
Client *clientv3.Client
}
// RunElectionOrDie behaves the same way as RunElection but panics if there is an error.
func RunElectionOrDie(ctx context.Context, config *LeaderElectionConfig) {
if err := RunElection(ctx, config); err != nil {
panic(err)
}
}
// RunElection starts a client with the provided config or panics.
// RunElection blocks until leader election loop is
// stopped by ctx or it has stopped holding the leader lease.
func RunElection(ctx context.Context, config *LeaderElectionConfig) error {
var memberID uint64
if config.MemberUniqueID != nil {
memberID = *config.MemberUniqueID
} else {
h := fnv.New64a()
if _, err := h.Write(append([]byte(config.Name), []byte(config.MemberID)...)); err != nil {
return err
}
memberID = h.Sum64()
}
ttl := config.LeaseDurationSeconds
r := &pb.LeaseGrantRequest{TTL: ttl, ID: int64(memberID)} //nolint
lease, err := clientv3.RetryLeaseClient(
config.EtcdConfig.Client,
).LeaseGrant(ctx, r)
if err != nil {
return errors.Wrap(err, "creating lease")
}
leaseID := clientv3.LeaseID(lease.ID)
s, err := concurrency.NewSession(
config.EtcdConfig.Client,
concurrency.WithTTL(int(lease.TTL)),
concurrency.WithLease(leaseID),
)
if err != nil {
return err
}
election := concurrency.NewElection(s, config.Name)
m := &member{
client: config.EtcdConfig.Client,
election: election,
callbacks: config.Callbacks,
memberID: config.MemberID,
weAreTheLeader: make(chan struct{}, 1),
leaseTTL: lease.TTL,
}
go m.tryToBeLeader(ctx)
m.watchLeaderChanges(ctx)
return nil
}
type member struct {
key string
client *clientv3.Client
election *concurrency.Election
isLeader bool
currentLeaderKey string
callbacks LeaderCallbacks
memberID string
weAreTheLeader chan struct{}
leaseTTL int64
}
func (m *member) watchLeaderChanges(ctx context.Context) {
observeCtx, observeCancel := context.WithCancel(ctx)
defer observeCancel()
changes := m.election.Observe(observeCtx)
watcher:
for {
select {
case <-ctx.Done():
break watcher
case <-m.weAreTheLeader:
m.isLeader = true
m.key = m.election.Key() // by this time, this should already be set, since Campaign has already returned
log.Debug("Marking self as leader with key", "id", m.memberID, "key", m.key)
case response := <-changes:
log.Debug("Leader Changes", "id", m.memberID, "response", response)
if len(response.Kvs) == 0 {
// There is a race condition where just after we stop being the leader
// if there are no more leaders, we might get a response with no key-values
// just before the response channel is closed or the context is cancel
// In that case, just continue and let one of those two things happen
continue
}
newLeaderKey := response.Kvs[0].Key
if m.isLeader && m.key != string(newLeaderKey) {
// We stopped being leaders
// exit the loop, so we cancel the observe context so we stop watching
// for new leaders. That will close the channel and make this function exit,
// which also makes the routine to finish and RunElection returns
break watcher
}
if m.currentLeaderKey != string(newLeaderKey) {
// we observed a leader, this could be us or someone else
m.currentLeaderKey = string(newLeaderKey)
m.callbacks.OnNewLeader(string(response.Kvs[0].Value))
}
}
}
// If we are here, either we have stopped being leaders or we lost the watcher
// Make sure we call OnStoppedLeading if we were the leader.
if m.isLeader {
m.callbacks.OnStoppedLeading()
}
log.Debug("Exiting watcher", "id", m.memberID)
}
func (m *member) tryToBeLeader(ctx context.Context) {
if err := m.election.Campaign(ctx, m.memberID); err != nil {
log.Error("Failed trying to become the leader", "err", err)
// Resign just in case we acquired leadership just before failing
if err := m.election.Resign(m.client.Ctx()); err != nil {
log.Warn("Failed to resign after we failed becoming the leader, this might not be a problem if we were never the leader", "err", err)
}
return
// TODO: what to do here?
// We probably want watchLeaderChanges to exit as well, since Run
// is expecting us to try to become the leader, but if we are here,
// we won't. So if we don't panic, we need to signal it somehow
}
// Inform the observer that we are the leader as soon as possible,
// so it can detect if we stop being it
m.weAreTheLeader <- struct{}{}
// Once we are the leader, start the routine to resign if context is canceled
go m.resignOnCancel(ctx)
// After becoming the leader, we wait for at least a lease TTL to wait for
// the previous leader to detect the new leadership (if there was one) and
// stop its processes
// TODO: is this too cautious?
log.Debug("timeout before OnStartedLeading", "id", m.memberID, "timeout", m.leaseTTL)
time.Sleep(time.Second * time.Duration(m.leaseTTL))
// We are the leader, execute our code
m.callbacks.OnStartedLeading(ctx)
// Here the routine dies if OnStartedLeading doesn't block, there is nothing else to do
}
func (m *member) resignOnCancel(ctx context.Context) {
<-ctx.Done()
if err := m.election.Resign(m.client.Ctx()); err != nil {
log.Error("Failed to resign after the context was canceled", "err", err)
}
}

169
pkg/etcd/election_test.go Normal file
View File

@@ -0,0 +1,169 @@
//go:build integration
// +build integration
package etcd_test
import (
"context"
"log"
"math/rand"
"sync"
"testing"
"time"
"github.com/kube-vip/kube-vip/pkg/etcd"
. "github.com/onsi/gomega"
clientv3 "go.etcd.io/etcd/client/v3"
"go.uber.org/zap"
)
func TestRunElectionWithMemberIDCollision(t *testing.T) {
t.Parallel()
g := NewWithT(t)
ctx := context.Background()
cli := client(g)
defer cli.Close()
electionName := randomElectionNameForTest("memberIDConflict")
log.Printf("Election name %s\n", electionName)
memberCtx, cancelMember1 := context.WithCancel(ctx)
config := &etcd.LeaderElectionConfig{
EtcdConfig: etcd.ClientConfig{
Client: cli,
},
Name: electionName,
MemberID: "my-host",
LeaseDurationSeconds: 1,
Callbacks: etcd.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
log.Println("I'm the leader!!!!")
log.Println("Renouncing as leader by canceling context")
cancelMember1()
},
OnNewLeader: func(identity string) {
log.Printf("New leader: %s\n", identity)
},
OnStoppedLeading: func() {
log.Println("I'm not the leader anymore")
},
},
}
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
g.Expect(etcd.RunElection(memberCtx, config)).To(Succeed())
}()
go func() {
defer wg.Done()
time.Sleep(time.Millisecond * 50) // make sure the first one becomes leader
g.Expect(etcd.RunElection(ctx, config)).Should(MatchError(ContainSubstring("creating lease")))
}()
wg.Wait()
}
func TestRunElectionWithTwoMembersAndReelection(t *testing.T) {
t.Parallel()
g := NewWithT(t)
ctx := context.Background()
cli := client(g)
defer cli.Close()
cliMember1 := client(g)
defer cliMember1.Close()
electionName := randomElectionNameForTest("steppingDown")
configBase := etcd.LeaderElectionConfig{
EtcdConfig: etcd.ClientConfig{
Client: cli,
},
Name: electionName,
LeaseDurationSeconds: 1,
}
member1Ctx, _ := context.WithCancel(ctx)
member2Ctx, cancelMember2 := context.WithCancel(ctx)
config1 := configBase
config1.EtcdConfig.Client = cliMember1
config1.MemberID = "my-host"
uniqueID := rand.Uint64()
config1.MemberUniqueID = &uniqueID
config1.Callbacks = baseCallbacksForName(config1.MemberID)
config1.Callbacks.OnStartedLeading = func(_ context.Context) {
log.Println("I'm my-host, the new leader!!!!")
log.Println("Losing the leadership on purpose by stopping renewing the lease")
g.Expect(cliMember1.Lease.Close()).To(Succeed())
log.Println("Member1 leases closed")
}
config2 := configBase
config2.MemberID = "my-other-host"
config2.Callbacks = baseCallbacksForName(config2.MemberID)
config2.Callbacks.OnStartedLeading = func(_ context.Context) {
log.Println("I'm my-other-host, the new leader!!!!")
log.Println("Renouncing as leader by canceling context")
cancelMember2()
}
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
g.Expect(etcd.RunElection(member1Ctx, &config1)).To(Succeed())
log.Println("Member1 routine done")
}()
go func() {
defer wg.Done()
time.Sleep(time.Millisecond * 50) // Make sure member1 becomes leader
g.Expect(etcd.RunElection(member2Ctx, &config2)).To(Succeed())
log.Println("Member2 routine done")
}()
wg.Wait()
}
func baseCallbacksForName(name string) etcd.LeaderCallbacks {
return etcd.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
log.Printf("[%s] I'm the new leader!!!!\n", name)
},
OnNewLeader: func(identity string) {
log.Printf("[%s] New leader: %s\n", name, identity)
},
OnStoppedLeading: func() {
log.Printf("[%s] I'm not the leader anymore\n", name)
},
}
}
func randomElectionNameForTest(name string) string {
return name + "-" + randomString(6)
}
const charSet = "0123456789abcdefghijklmnopqrstuvwxyz"
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
func randomString(n int) string {
result := make([]byte, n)
for i := range result {
result[i] = charSet[rnd.Intn(len(charSet))]
}
return string(result)
}
func client(g Gomega) *clientv3.Client {
c, err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:2379"},
Logger: zap.NewNop(),
})
g.Expect(err).NotTo(HaveOccurred())
return c
}

153
pkg/etcd/etcd_suite_test.go Normal file
View File

@@ -0,0 +1,153 @@
//go:build integration
// +build integration
package etcd_test
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strconv"
"testing"
"time"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
etcdVersion = "v3.5.9"
etcdBinDir = "bin"
etcdBinPath = etcdBinDir + "/etcd"
downloadURL = "https://storage.googleapis.com/etcd"
tmpDownloadFile = "etcd.tar.gz"
pidFile = "etcd.pid"
)
func TestMain(m *testing.M) {
logrus.SetLevel(logrus.DebugLevel)
ctx := context.Background()
expectSuccess(startEtcd(ctx), "starting etcd")
os.Exit(runTestsWithCleanup(m, func() {
expectSuccess(stopEtcd(), "stopping etcd")
}))
}
func runTestsWithCleanup(m *testing.M, cleanup func()) int {
defer cleanup()
return m.Run()
}
func expectSuccess(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s\n", msg, err)
}
}
func startEtcd(ctx context.Context) error {
if _, err := os.Stat(pidFile); err == nil {
log.Println("Etcd already running, reusing")
return nil
}
etcdPath, err := installEtcd(ctx)
if err != nil {
errors.Wrap(err, "installing etcd for tests")
}
etcdCmd := exec.Command(etcdPath, "--data-dir", "./etcd-data")
if os.Getenv("ETCD_SERVER_LOGS") == "true" {
log.Println("Enabling etcd server logs")
etcdCmd.Stdout = os.Stdout
etcdCmd.Stderr = os.Stderr
}
log.Println("Starting etcd")
if err := etcdCmd.Start(); err != nil {
errors.Wrap(err, "starting etcd for tests")
}
if err := os.WriteFile(pidFile, []byte(strconv.Itoa(etcdCmd.Process.Pid)), 0o600); err != nil {
return err
}
log.Println("Waiting for etcd to be up")
time.Sleep(time.Second)
return nil
}
func installEtcd(ctx context.Context) (string, error) {
projectRoot, err := filepath.Abs("../../")
if err != nil {
return "", err
}
binDir := filepath.Join(projectRoot, etcdBinDir)
etcdPath := filepath.Join(projectRoot, etcdBinPath)
if _, err := os.Stat(etcdPath); err == nil {
log.Println("Etcd already installed, skipping")
return etcdPath, nil
}
if err := os.MkdirAll(binDir, 0o755); err != nil {
return "", err
}
download := fmt.Sprintf("%s/%s/etcd-%s-linux-amd64.tar.gz", downloadURL, etcdVersion, etcdVersion)
// Hacky to run bash, but simplifies this code a lot
cmd := fmt.Sprintf("curl -sL %s | tar -xzvf - -C %s --strip-components=1", download, binDir)
out, err := exec.CommandContext(ctx, "bash", "-c", cmd).CombinedOutput()
if err != nil {
return "", errors.Wrapf(err, "downloading etcd: %s", string(out))
}
return etcdPath, nil
}
func stopEtcd() error {
if os.Getenv("REUSE_ETCD") == "true" {
log.Println("REUSE_ETCD=true, leaving etcd running")
return nil
}
if _, err := os.Stat(pidFile); os.IsNotExist(err) {
log.Println("Etcd pid file doesn't exit, skipping cleanup")
return nil
}
dat, err := os.ReadFile(pidFile)
if err != nil {
return err
}
pid, err := strconv.Atoi(string(dat))
if err != nil {
return err
}
etcdProcess, err := os.FindProcess(pid)
if err != nil {
return err
}
log.Println("Stopping etcd")
if err := etcdProcess.Kill(); err != nil {
return errors.Wrap(err, "Failed stopping etcd")
}
log.Println("Deleting etcd data")
if err := os.RemoveAll("./etcd-data"); err != nil {
return errors.Wrap(err, "deleting etcd data")
}
log.Println("Deleting etcd pid file")
if err := os.RemoveAll(pidFile); err != nil {
return errors.Wrap(err, "deleting pid file")
}
return nil
}

482
pkg/instance/instance.go Normal file
View File

@@ -0,0 +1,482 @@
package instance
import (
"fmt"
"net"
"strconv"
"strings"
"log/slog"
log "log/slog"
"github.com/vishvananda/netlink"
v1 "k8s.io/api/core/v1"
"github.com/kube-vip/kube-vip/pkg/arp"
"github.com/kube-vip/kube-vip/pkg/cluster"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/networkinterface"
"github.com/kube-vip/kube-vip/pkg/sysctl"
"github.com/kube-vip/kube-vip/pkg/vip"
)
// Instance defines an instance of everything needed to manage vips
type Instance struct {
// Virtual IP / Load Balancer configuration
VIPConfigs []*kubevip.Config
// cluster instances
Clusters []*cluster.Cluster
// Service uses DHCP
IsDHCP bool
DHCPInterface string
DHCPInterfaceHwaddr string
DHCPInterfaceIP string
DHCPHostname string
DHCPClient *vip.DHCPClient
// External Gateway IP the service is forwarded from
UPNPGatewayIPs []string
// Kubernetes service mapping
ServiceSnapshot *v1.Service
}
type Port struct {
Port uint16
Type string
}
func NewInstance(svc *v1.Service, config *kubevip.Config, intfMgr *networkinterface.Manager, arpMgr *arp.Manager) (*Instance, error) {
instanceAddresses := FetchServiceAddresses(svc)
//instanceUID := string(svc.UID)
var newVips []*kubevip.Config
var link netlink.Link
var err error
for _, address := range instanceAddresses {
// Detect if we're using a specific interface for services
var svcInterface string
svcInterface = svc.Annotations[kubevip.ServiceInterface] // If the service has a specific interface defined, then use it
if svcInterface == kubevip.Auto {
link, err = autoFindInterface(address)
if err != nil {
log.Error("automatically discover network interface for annotated IP", "address", address, "err", err)
} else {
if link == nil {
log.Error("automatically discover network interface for annotated IP address", "address", address)
}
}
if link == nil {
svcInterface = ""
} else {
svcInterface = getAutoInterfaceName(link, config.Interface)
}
}
// If it is still blank then use the
if svcInterface == "" {
switch config.ServicesInterface {
case kubevip.Auto:
link, err = autoFindInterface(address)
if err != nil {
log.Error("failed to automatically discover network interface for address", "ip", address, "err", err, "interface", config.Interface)
} else if link == nil {
log.Error("failed to automatically discover network interface for address", "ip", address, "defaulting to", config.Interface)
}
svcInterface = getAutoInterfaceName(link, config.Interface)
case "":
svcInterface = config.Interface
default:
svcInterface = config.ServicesInterface
}
}
if link == nil {
if link, err = netlink.LinkByName(svcInterface); err != nil {
return nil, fmt.Errorf("failed to get interface %s: %w", svcInterface, err)
}
if link == nil {
return nil, fmt.Errorf("failed to get interface %s", svcInterface)
}
}
cidrs := vip.Split(config.VIPSubnet)
ipv4AutoSubnet := false
ipv6AutoSubnet := false
if cidrs[0] == kubevip.Auto {
ipv4AutoSubnet = true
}
if len(cidrs) > 1 && cidrs[1] == kubevip.Auto {
ipv6AutoSubnet = true
}
if (config.Address != "" || config.VIP != "") && (ipv4AutoSubnet || ipv6AutoSubnet) {
return nil, fmt.Errorf("auto subnet discovery cannot be used if VIP address was provided")
}
subnet := ""
var err error
if vip.IsIPv4(address) {
if ipv4AutoSubnet {
subnet, err = autoFindSubnet(link, address)
if err != nil {
return nil, fmt.Errorf("failed to automatically find subnet for service %s/%s with IP address %s on interface %s: %w", svc.Namespace, svc.Name, address, svcInterface, err)
}
} else {
if cidrs[0] != "" && cidrs[0] != kubevip.Auto {
subnet = cidrs[0]
} else {
subnet = "32"
}
}
} else {
if ipv6AutoSubnet {
subnet, err = autoFindSubnet(link, address)
if err != nil {
return nil, fmt.Errorf("failed to automatically find subnet for service %s/%s with IP address %s on interface %s: %w", svc.Namespace, svc.Name, address, svcInterface, err)
}
} else {
if len(cidrs) > 1 && cidrs[1] != "" && cidrs[1] != kubevip.Auto {
subnet = cidrs[1]
} else {
subnet = "128"
}
}
}
// Generate new Virtual IP configuration
newVips = append(newVips, &kubevip.Config{
VIP: address,
Interface: svcInterface,
SingleNode: true,
EnableARP: config.EnableARP,
EnableBGP: config.EnableBGP,
VIPSubnet: subnet,
EnableRoutingTable: config.EnableRoutingTable,
RoutingTableID: config.RoutingTableID,
RoutingTableType: config.RoutingTableType,
RoutingProtocol: config.RoutingProtocol,
ArpBroadcastRate: config.ArpBroadcastRate,
EnableServiceSecurity: config.EnableServiceSecurity,
DNSMode: config.DNSMode,
DisableServiceUpdates: config.DisableServiceUpdates,
EnableServicesElection: config.EnableServicesElection,
KubernetesLeaderElection: kubevip.KubernetesLeaderElection{
EnableLeaderElection: config.EnableLeaderElection,
},
})
}
// Create new service
instance := &Instance{
//UID: instanceUID,
//VIPs: instanceAddresses,
ServiceSnapshot: svc,
}
// for _, port := range svc.Spec.Ports {
// instance.ExternalPorts = append(instance.ExternalPorts, Port{
// Port: uint16(port.Port), //nolint
// Type: string(port.Protocol),
// })
// }
if svc.Annotations != nil {
instance.DHCPInterfaceHwaddr = svc.Annotations[kubevip.HwAddrKey]
instance.DHCPInterfaceIP = svc.Annotations[kubevip.RequestedIP]
instance.DHCPHostname = svc.Annotations[kubevip.LoadbalancerHostname]
}
configPorts := make([]kubevip.Port, 0)
for _, p := range svc.Spec.Ports {
configPorts = append(configPorts, kubevip.Port{
Type: string(p.Protocol),
Port: int(p.Port),
})
}
// Generate Load Balancer config
newLB := kubevip.LoadBalancer{
Name: fmt.Sprintf("%s-load-balancer", svc.Name),
Ports: configPorts,
BindToVip: true,
}
for _, vip := range newVips {
// Add Load Balancer Configuration
vip.LoadBalancers = append(vip.LoadBalancers, newLB)
}
// Create Add configuration to the new service
instance.VIPConfigs = newVips
// If this was purposely created with the address 0.0.0.0,
// we will create a macvlan on the main interface and a DHCP client
// TODO: Consider how best to handle DHCP with multiple addresses
if len(instanceAddresses) == 1 && instanceAddresses[0] == "0.0.0.0" {
err := instance.startDHCP()
if err != nil {
return nil, err
}
select {
case err := <-instance.DHCPClient.ErrorChannel():
return nil, fmt.Errorf("error starting DHCP for %s/%s: error: %s",
instance.ServiceSnapshot.Namespace, instance.ServiceSnapshot.Name, err)
case ip := <-instance.DHCPClient.IPChannel():
instance.VIPConfigs[0].Interface = instance.DHCPInterface
instance.VIPConfigs[0].VIP = ip
instance.DHCPInterfaceIP = ip
}
}
for _, vipConfig := range instance.VIPConfigs {
c, err := cluster.InitCluster(vipConfig, false, intfMgr, arpMgr)
if err != nil {
log.Error("Failed to add Service %s/%s", svc.Namespace, svc.Name)
return nil, err
}
for i := range c.Network {
c.Network[i].SetServicePorts(svc)
}
instance.Clusters = append(instance.Clusters, c)
log.Info("(svcs) adding VIP", "ip", vipConfig.VIP, "interface", vipConfig.Interface, "namespace", svc.Namespace, "name", svc.Name)
}
return instance, nil
}
func autoFindInterface(ip string) (netlink.Link, error) {
links, err := netlink.LinkList()
if err != nil {
return nil, fmt.Errorf("failed to list network interfaces: %w", err)
}
address := net.ParseIP(ip)
family := netlink.FAMILY_V4
if address.To4() == nil {
family = netlink.FAMILY_V6
}
for _, link := range links {
addr, err := netlink.AddrList(link, family)
if err != nil {
return nil, fmt.Errorf("failed to get IP addresses for interface %s: %w", link.Attrs().Name, err)
}
for _, a := range addr {
if a.IPNet.Contains(address) {
return link, nil
}
}
}
return nil, nil
}
func autoFindSubnet(link netlink.Link, ip string) (string, error) {
address := net.ParseIP(ip)
family := netlink.FAMILY_V4
if address.To4() == nil {
family = netlink.FAMILY_V6
}
addr, err := netlink.AddrList(link, family)
if err != nil {
return "", fmt.Errorf("failed to get IP addresses for interface %s: %w", link.Attrs().Name, err)
}
for _, a := range addr {
if a.IPNet.Contains(address) {
m, _ := a.IPNet.Mask.Size()
return strconv.Itoa(m), nil
}
}
return "", fmt.Errorf("failed to find suitable subnet for address %s", ip)
}
func getAutoInterfaceName(link netlink.Link, defaultInterface string) string {
if link == nil {
return defaultInterface
}
return link.Attrs().Name
}
func (i *Instance) startDHCP() error {
if len(i.VIPConfigs) != 1 {
return fmt.Errorf("DHCP requires exactly 1 VIP config, got: %v", len(i.VIPConfigs))
}
parent, err := netlink.LinkByName(i.VIPConfigs[0].Interface)
if err != nil {
return fmt.Errorf("error finding VIP Interface, for building DHCP Link : %v", err)
}
// Generate name from UID
interfaceName := fmt.Sprintf("vip-%s", i.ServiceSnapshot.UID[0:8])
// Check if the interface doesn't exist first
iface, err := net.InterfaceByName(interfaceName)
if err != nil {
log.Info("creating new macvlan interface for DHCP", "interface", interfaceName)
hwaddr, err := net.ParseMAC(i.DHCPInterfaceHwaddr)
if i.DHCPInterfaceHwaddr != "" && err != nil {
return err
} else if hwaddr == nil {
hwaddr, err = net.ParseMAC(vip.GenerateMac())
if err != nil {
return err
}
}
log.Info("new macvlan interface", "interface", interfaceName, "hardware address", hwaddr)
mac := &netlink.Macvlan{
LinkAttrs: netlink.LinkAttrs{
Name: interfaceName,
ParentIndex: parent.Attrs().Index,
HardwareAddr: hwaddr,
},
Mode: netlink.MACVLAN_MODE_DEFAULT,
}
err = netlink.LinkAdd(mac)
if err != nil {
return fmt.Errorf("could not add %s: %v", interfaceName, err)
}
err = netlink.LinkSetUp(mac)
if err != nil {
return fmt.Errorf("could not bring up interface [%s] : %v", interfaceName, err)
}
iface, err = net.InterfaceByName(interfaceName)
if err != nil {
return fmt.Errorf("error finding new DHCP interface by name [%v]", err)
}
} else {
log.Info("Using existing macvlan interface for DHCP", "interface", interfaceName)
}
// Default rp_filter setting (https://github.com/kube-vip/kube-vip/issues/1170)
rpfilterSetting := "0"
// Check if we need to set an override rp_filter value for the interface
if i.ServiceSnapshot.Annotations[kubevip.RPFilter] != "" {
// Check the rp_filter value
rpFilter, err := strconv.Atoi(i.ServiceSnapshot.Annotations[kubevip.RPFilter])
if err != nil {
slog.Error("[DHCP] unable to process rp_filter", "value", rpFilter)
} else {
if rpFilter >= 0 && rpFilter < 3 { // Ensure the value is 0,1,2
rpfilterSetting = i.ServiceSnapshot.Annotations[kubevip.RPFilter]
} else {
slog.Error("[DHCP] rp_filter value not within range 0-2", "value", rpFilter)
}
}
}
err = sysctl.WriteProcSys("/proc/sys/net/ipv4/conf/"+interfaceName+"/rp_filter", rpfilterSetting)
if err != nil {
slog.Error("[DHCP] unable to write rp_filter", "value", rpfilterSetting, "err", err)
}
var initRebootFlag bool
if i.DHCPInterfaceIP != "" {
initRebootFlag = true
}
client := vip.NewDHCPClient(iface, initRebootFlag, i.DHCPInterfaceIP)
// Add hostname to dhcp client if annotated
if i.DHCPHostname != "" {
log.Info("Hostname specified for dhcp lease", "interface", interfaceName, "hostname", i.DHCPHostname)
client.WithHostName(i.DHCPHostname)
}
go client.Start()
// Set that DHCP is enabled
i.IsDHCP = true
// Set the name of the interface so that it can be removed on Service deletion
i.DHCPInterface = interfaceName
i.DHCPInterfaceHwaddr = iface.HardwareAddr.String()
// Add the client so that we can call it to stop function
i.DHCPClient = client
return nil
}
// FetchIngressAddresses tries to get the addresses from status.loadBalancerIP
func FetchLoadBalancerIngressAddresses(s *v1.Service) []string {
// If the service has no status, return empty
lbStatusAddresses := []string{}
if len(s.Status.LoadBalancer.Ingress) == 0 {
return lbStatusAddresses
}
for _, ingress := range s.Status.LoadBalancer.Ingress {
if ingress.IP != "" {
lbStatusAddresses = append(lbStatusAddresses, ingress.IP)
}
// TODO: Handle hostname if needed
}
return lbStatusAddresses
}
// FetchServiceAddresses tries to get the addresses from annotations
// kube-vip.io/loadbalancerIPs, then from spec.loadbalancerIP
func FetchServiceAddresses(s *v1.Service) []string {
annotationAvailable := false
if s.Annotations != nil {
if v, annotationAvailable := s.Annotations[kubevip.LoadbalancerIPAnnotation]; annotationAvailable {
ips := strings.Split(v, ",")
var trimmedIPs []string
for _, ip := range ips {
trimmedIPs = append(trimmedIPs, strings.TrimSpace(ip))
}
return trimmedIPs
}
}
lbStatusAddresses := []string{}
if !annotationAvailable {
if len(s.Status.LoadBalancer.Ingress) > 0 {
for _, ingress := range s.Status.LoadBalancer.Ingress {
lbStatusAddresses = append(lbStatusAddresses, ingress.IP)
}
}
}
lbIP := net.ParseIP(s.Spec.LoadBalancerIP)
isLbIPv4 := vip.IsIPv4(s.Spec.LoadBalancerIP)
if len(lbStatusAddresses) > 0 {
for _, a := range lbStatusAddresses {
if lbStatusIP := net.ParseIP(a); lbStatusIP != nil && lbIP != nil && vip.IsIPv4(a) == isLbIPv4 && !lbIP.Equal(lbStatusIP) {
return []string{s.Spec.LoadBalancerIP}
}
}
return lbStatusAddresses
}
if s.Spec.LoadBalancerIP != "" {
return []string{s.Spec.LoadBalancerIP}
}
return []string{}
}
func FindServiceInstance(svc *v1.Service, instances []*Instance) *Instance {
log.Debug("finding service", "UID", svc.UID)
for i := range instances {
log.Debug("saved service", "instance", i, "UID", instances[i].ServiceSnapshot.UID)
if instances[i].ServiceSnapshot.UID == svc.UID {
return instances[i]
}
}
return nil
}

741
pkg/iptables/iptables.go Normal file
View File

@@ -0,0 +1,741 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 iptables
import (
"bytes"
"fmt"
"io"
"net"
"os/exec"
"regexp"
"strconv"
"strings"
"syscall"
)
// Adds the output of stderr to exec.ExitError
type Error struct {
exec.ExitError
cmd exec.Cmd
msg string
exitStatus *int //for overriding
}
func (e *Error) ExitStatus() int {
if e.exitStatus != nil {
return *e.exitStatus
}
return e.Sys().(syscall.WaitStatus).ExitStatus()
}
func (e *Error) Error() string {
return fmt.Sprintf("running %v: exit status %v: %v", e.cmd.Args, e.ExitStatus(), e.msg)
}
// IsNotExist returns true if the error is due to the chain or rule not existing
func (e *Error) IsNotExist() bool {
if e.ExitStatus() != 1 {
return false
}
msgNoRuleExist := "Bad rule (does a matching rule exist in that chain?).\n"
msgNoChainExist := "No chain/target/match by that name.\n"
return strings.Contains(e.msg, msgNoRuleExist) || strings.Contains(e.msg, msgNoChainExist)
}
// Protocol to differentiate between IPv4 and IPv6
type Protocol byte
const (
ProtocolIPv4 Protocol = iota
ProtocolIPv6
)
const (
TableFilter = "filter"
TableMangle = "mangle"
TableNat = "nat"
ChainInput = "INPUT"
ChainPREROUTING = "PREROUTING"
ChainPOSTROUTING = "POSTROUTING"
)
type IPTables struct {
path string
proto Protocol
hasCheck bool
hasWait bool
waitSupportSecond bool
hasRandomFully bool
v1 int
v2 int
v3 int
mode string // the underlying iptables operating mode, e.g. nf_tables
timeout int // time to wait for the iptables lock, default waits forever
nftables bool
}
// Stat represents a structured statistic entry.
type Stat struct {
Packets uint64 `json:"pkts"`
Bytes uint64 `json:"bytes"`
Target string `json:"target"`
Protocol string `json:"prot"`
Opt string `json:"opt"`
Input string `json:"in"`
Output string `json:"out"`
Source *net.IPNet `json:"source"`
Destination *net.IPNet `json:"destination"`
Options string `json:"options"`
}
type Option func(*IPTables)
func IPFamily(proto Protocol) Option {
return func(ipt *IPTables) {
ipt.proto = proto
}
}
func Timeout(timeout int) Option {
return func(ipt *IPTables) {
ipt.timeout = timeout
}
}
func EnableNFTables(enable bool) Option {
return func(ipt *IPTables) {
ipt.nftables = enable
}
}
// New creates a new IPTables configured with the options passed as parameter.
// For backwards compatibility, by default always uses IPv4 and timeout 0.
// i.e. you can create an IPv6 IPTables using a timeout of 5 seconds passing
// the IPFamily and Timeout options as follow:
//
// ip6t := New(IPFamily(ProtocolIPv6), Timeout(5))
func New(opts ...Option) (*IPTables, error) {
ipt := &IPTables{
proto: ProtocolIPv4,
timeout: 0,
}
for _, opt := range opts {
opt(ipt)
}
path, err := exec.LookPath(getIptablesCommand(ipt.proto, ipt.nftables))
if err != nil {
return nil, err
}
ipt.path = path
vstring, err := getIptablesVersionString(path)
if err != nil {
return nil, fmt.Errorf("could not get iptables version: %v", err)
}
v1, v2, v3, mode, err := extractIptablesVersion(vstring)
if err != nil {
return nil, fmt.Errorf("failed to extract iptables version from [%s]: %v", vstring, err)
}
ipt.v1 = v1
ipt.v2 = v2
ipt.v3 = v3
ipt.mode = mode
checkPresent, waitPresent, waitSupportSecond, randomFullyPresent := getIptablesCommandSupport(v1, v2, v3)
ipt.hasCheck = checkPresent
ipt.hasWait = waitPresent
ipt.waitSupportSecond = waitSupportSecond
ipt.hasRandomFully = randomFullyPresent
return ipt, nil
}
// New creates a new IPTables for the given proto.
// The proto will determine which command is used, either "iptables" or "ip6tables".
func NewWithProtocol(proto Protocol) (*IPTables, error) {
return New(IPFamily(proto), Timeout(0))
}
// Proto returns the protocol used by this IPTables.
func (ipt *IPTables) Proto() Protocol {
return ipt.proto
}
// Exists checks if given rulespec in specified table/chain exists
func (ipt *IPTables) Exists(table, chain string, rulespec ...string) (bool, error) {
if !ipt.hasCheck {
return ipt.existsForOldIptables(table, chain, rulespec)
}
cmd := append([]string{"-t", table, "-C", chain}, rulespec...)
err := ipt.run(cmd...)
eerr, eok := err.(*Error)
switch {
case err == nil:
return true, nil
case eok && eerr.ExitStatus() == 1:
return false, nil
default:
return false, err
}
}
// Insert inserts rulespec to specified table/chain (in specified pos)
func (ipt *IPTables) Insert(table, chain string, pos int, rulespec ...string) error {
cmd := append([]string{"-t", table, "-I", chain, strconv.Itoa(pos)}, rulespec...)
return ipt.run(cmd...)
}
// InsertUnique acts like Insert except that it won't insert a duplicate (no matter the position in the chain)
func (ipt *IPTables) InsertUnique(table, chain string, pos int, rulespec ...string) error {
exists, err := ipt.Exists(table, chain, rulespec...)
if err != nil {
return err
}
if !exists {
return ipt.Insert(table, chain, pos, rulespec...)
}
return nil
}
// Append appends rulespec to specified table/chain
func (ipt *IPTables) Append(table, chain string, rulespec ...string) error {
cmd := append([]string{"-t", table, "-A", chain}, rulespec...)
return ipt.run(cmd...)
}
// AppendUnique acts like Append except that it won't add a duplicate
func (ipt *IPTables) AppendUnique(table, chain string, rulespec ...string) error {
exists, err := ipt.Exists(table, chain, rulespec...)
if err != nil {
return err
}
if !exists {
return ipt.Append(table, chain, rulespec...)
}
return nil
}
// Delete removes rulespec in specified table/chain
func (ipt *IPTables) Delete(table, chain string, rulespec ...string) error {
cmd := append([]string{"-t", table, "-D", chain}, rulespec...)
return ipt.run(cmd...)
}
func (ipt *IPTables) DeleteIfExists(table, chain string, rulespec ...string) error {
exists, err := ipt.Exists(table, chain, rulespec...)
if err == nil && exists {
err = ipt.Delete(table, chain, rulespec...)
}
return err
}
// List rules in specified table/chain
func (ipt *IPTables) ListByID(table, chain string, id int) (string, error) {
args := []string{"-t", table, "-S", chain, strconv.Itoa(id)}
rule, err := ipt.executeList(args)
if err != nil {
return "", err
}
return rule[0], nil
}
// List rules in specified table/chain
func (ipt *IPTables) List(table, chain string) ([]string, error) {
args := []string{"-t", table, "-S", chain}
return ipt.executeList(args)
}
// List rules (with counters) in specified table/chain
func (ipt *IPTables) ListWithCounters(table, chain string) ([]string, error) {
args := []string{"-t", table, "-v", "-S", chain}
return ipt.executeList(args)
}
// ListChains returns a slice containing the name of each chain in the specified table.
func (ipt *IPTables) ListChains(table string) ([]string, error) {
args := []string{"-t", table, "-S"}
result, err := ipt.executeList(args)
if err != nil {
return nil, err
}
// Iterate over rules to find all default (-P) and user-specified (-N) chains.
// Chains definition always come before rules.
// Format is the following:
// -P OUTPUT ACCEPT
// -N Custom
var chains []string
for _, val := range result {
if strings.HasPrefix(val, "-P") || strings.HasPrefix(val, "-N") {
chains = append(chains, strings.Fields(val)[1])
} else {
break
}
}
return chains, nil
}
// '-S' is fine with non existing rule index as long as the chain exists
// therefore pass index 1 to reduce overhead for large chains
func (ipt *IPTables) ChainExists(table, chain string) (bool, error) {
err := ipt.run("-t", table, "-S", chain, "1")
eerr, eok := err.(*Error)
switch {
case err == nil:
return true, nil
case eok && eerr.ExitStatus() == 1:
return false, nil
default:
return false, err
}
}
// Stats lists rules including the byte and packet counts
func (ipt *IPTables) Stats(table, chain string) ([][]string, error) {
args := []string{"-t", table, "-L", chain, "-n", "-v", "-x"}
lines, err := ipt.executeList(args)
if err != nil {
return nil, err
}
appendSubnet := func(addr string) string {
if strings.IndexByte(addr, byte('/')) < 0 {
if strings.IndexByte(addr, '.') < 0 {
return addr + "/128"
}
return addr + "/32"
}
return addr
}
ipv6 := ipt.proto == ProtocolIPv6
rows := [][]string{}
for i, line := range lines {
// Skip over chain name and field header
if i < 2 {
continue
}
// Fields:
// 0=pkts 1=bytes 2=target 3=prot 4=opt 5=in 6=out 7=source 8=destination 9=options
line = strings.TrimSpace(line)
fields := strings.Fields(line)
// The ip6tables verbose output cannot be naively split due to the default "opt"
// field containing 2 single spaces.
if ipv6 {
// Check if field 6 is "opt" or "source" address
dest := fields[6]
ip, _, _ := net.ParseCIDR(dest)
if ip == nil {
ip = net.ParseIP(dest)
}
// If we detected a CIDR or IP, the "opt" field is empty.. insert it.
if ip != nil {
f := []string{}
f = append(f, fields[:4]...)
f = append(f, " ") // Empty "opt" field for ip6tables
f = append(f, fields[4:]...)
fields = f
}
}
// Adjust "source" and "destination" to include netmask, to match regular
// List output
fields[7] = appendSubnet(fields[7])
fields[8] = appendSubnet(fields[8])
// Combine "options" fields 9... into a single space-delimited field.
options := fields[9:]
fields = fields[:9]
fields = append(fields, strings.Join(options, " "))
rows = append(rows, fields)
}
return rows, nil
}
// ParseStat parses a single statistic row into a Stat struct. The input should
// be a string slice that is returned from calling the Stat method.
func (ipt *IPTables) ParseStat(stat []string) (parsed Stat, err error) {
// For forward-compatibility, expect at least 10 fields in the stat
if len(stat) < 10 {
return parsed, fmt.Errorf("stat contained fewer fields than expected")
}
// Convert the fields that are not plain strings
parsed.Packets, err = strconv.ParseUint(stat[0], 0, 64)
if err != nil {
return parsed, fmt.Errorf(err.Error(), "could not parse packets")
}
parsed.Bytes, err = strconv.ParseUint(stat[1], 0, 64)
if err != nil {
return parsed, fmt.Errorf(err.Error(), "could not parse bytes")
}
_, parsed.Source, err = net.ParseCIDR(stat[7])
if err != nil {
return parsed, fmt.Errorf(err.Error(), "could not parse source")
}
_, parsed.Destination, err = net.ParseCIDR(stat[8])
if err != nil {
return parsed, fmt.Errorf(err.Error(), "could not parse destination")
}
// Put the fields that are strings
parsed.Target = stat[2]
parsed.Protocol = stat[3]
parsed.Opt = stat[4]
parsed.Input = stat[5]
parsed.Output = stat[6]
parsed.Options = stat[9]
return parsed, nil
}
// StructuredStats returns statistics as structured data which may be further
// parsed and marshaled.
func (ipt *IPTables) StructuredStats(table, chain string) ([]Stat, error) {
rawStats, err := ipt.Stats(table, chain)
if err != nil {
return nil, err
}
structStats := []Stat{}
for _, rawStat := range rawStats {
stat, err := ipt.ParseStat(rawStat)
if err != nil {
return nil, err
}
structStats = append(structStats, stat)
}
return structStats, nil
}
func (ipt *IPTables) executeList(args []string) ([]string, error) {
var stdout bytes.Buffer
if err := ipt.runWithOutput(args, &stdout); err != nil {
return nil, err
}
rules := strings.Split(stdout.String(), "\n")
// strip trailing newline
if len(rules) > 0 && rules[len(rules)-1] == "" {
rules = rules[:len(rules)-1]
}
for i, rule := range rules {
rules[i] = filterRuleOutput(rule)
}
return rules, nil
}
// NewChain creates a new chain in the specified table.
// If the chain already exists, it will result in an error.
func (ipt *IPTables) NewChain(table, chain string) error {
return ipt.run("-t", table, "-N", chain)
}
const existsErr = 1
// ClearChain flushed (deletes all rules) in the specified table/chain.
// If the chain does not exist, a new one will be created
func (ipt *IPTables) ClearChain(table, chain string) error {
err := ipt.NewChain(table, chain)
eerr, eok := err.(*Error)
switch {
case err == nil:
return nil
case eok && eerr.ExitStatus() == existsErr:
// chain already exists. Flush (clear) it.
return ipt.run("-t", table, "-F", chain)
default:
return err
}
}
// RenameChain renames the old chain to the new one.
func (ipt *IPTables) RenameChain(table, oldChain, newChain string) error {
return ipt.run("-t", table, "-E", oldChain, newChain)
}
// DeleteChain deletes the chain in the specified table.
// The chain must be empty
func (ipt *IPTables) DeleteChain(table, chain string) error {
return ipt.run("-t", table, "-X", chain)
}
func (ipt *IPTables) ClearAndDeleteChain(table, chain string) error {
exists, err := ipt.ChainExists(table, chain)
if err != nil || !exists {
return err
}
err = ipt.run("-t", table, "-F", chain)
if err == nil {
err = ipt.run("-t", table, "-X", chain)
}
return err
}
func (ipt *IPTables) ClearAll() error {
return ipt.run("-F")
}
func (ipt *IPTables) DeleteAll() error {
return ipt.run("-X")
}
// ChangePolicy changes policy on chain to target
func (ipt *IPTables) ChangePolicy(table, chain, target string) error {
return ipt.run("-t", table, "-P", chain, target)
}
// Check if the underlying iptables command supports the --random-fully flag
func (ipt *IPTables) HasRandomFully() bool {
return ipt.hasRandomFully
}
// Return version components of the underlying iptables command
func (ipt *IPTables) GetIptablesVersion() (int, int, int) {
return ipt.v1, ipt.v2, ipt.v3
}
// run runs an iptables command with the given arguments, ignoring
// any stdout output
func (ipt *IPTables) run(args ...string) error {
return ipt.runWithOutput(args, nil)
}
// runWithOutput runs an iptables command with the given arguments,
// writing any stdout output to the given writer
func (ipt *IPTables) runWithOutput(args []string, stdout io.Writer) error {
args = append([]string{ipt.path}, args...)
if ipt.hasWait {
args = append(args, "--wait")
if ipt.timeout != 0 && ipt.waitSupportSecond {
args = append(args, strconv.Itoa(ipt.timeout))
}
} else {
fmu, err := newXtablesFileLock()
if err != nil {
return err
}
ul, err := fmu.tryLock()
if err != nil {
syscall.Close(fmu.fd)
return err
}
defer func() {
_ = ul.Unlock()
}()
}
var stderr bytes.Buffer
cmd := exec.Cmd{
Path: ipt.path,
Args: args,
Stdout: stdout,
Stderr: &stderr,
}
if err := cmd.Run(); err != nil {
switch e := err.(type) {
case *exec.ExitError:
return &Error{*e, cmd, stderr.String(), nil}
default:
return err
}
}
return nil
}
// getIptablesCommand returns the correct command for the given protocol, either "iptables" or "ip6tables".
func getIptablesCommand(proto Protocol, nftables bool) string {
if proto == ProtocolIPv6 {
if nftables {
return "ip6tables-nft"
}
return "ip6tables-legacy"
}
if nftables {
return "iptables-nft"
}
return "iptables-legacy"
}
// Checks if iptables has the "-C" and "--wait" flag
func getIptablesCommandSupport(v1 int, v2 int, v3 int) (bool, bool, bool, bool) {
return iptablesHasCheckCommand(v1, v2, v3), iptablesHasWaitCommand(v1, v2, v3), iptablesWaitSupportSecond(v1, v2), iptablesHasRandomFully(v1, v2, v3)
}
// getIptablesVersion returns the first three components of the iptables version
// and the operating mode (e.g. nf_tables or legacy)
// e.g. "iptables v1.3.66" would return (1, 3, 66, legacy, nil)
func extractIptablesVersion(str string) (int, int, int, string, error) {
versionMatcher := regexp.MustCompile(`v([0-9]+)\.([0-9]+)\.([0-9]+)(?:\s+\((\w+))?`)
result := versionMatcher.FindStringSubmatch(str)
if result == nil {
return 0, 0, 0, "", fmt.Errorf("no iptables version found in string: %s", str)
}
v1, err := strconv.Atoi(result[1])
if err != nil {
return 0, 0, 0, "", err
}
v2, err := strconv.Atoi(result[2])
if err != nil {
return 0, 0, 0, "", err
}
v3, err := strconv.Atoi(result[3])
if err != nil {
return 0, 0, 0, "", err
}
mode := "legacy"
if result[4] != "" {
mode = result[4]
}
return v1, v2, v3, mode, nil
}
// Runs "iptables --version" to get the version string
func getIptablesVersionString(path string) (string, error) {
cmd := exec.Command(path, "--version")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return "", err
}
return out.String(), nil
}
// Checks if an iptables version is after 1.4.11, when --check was added
func iptablesHasCheckCommand(v1 int, v2 int, v3 int) bool {
if v1 > 1 {
return true
}
if v1 == 1 && v2 > 4 {
return true
}
if v1 == 1 && v2 == 4 && v3 >= 11 {
return true
}
return false
}
// Checks if an iptables version is after 1.4.20, when --wait was added
func iptablesHasWaitCommand(v1 int, v2 int, v3 int) bool { //nolint
if v1 > 1 {
return true
}
if v1 == 1 && v2 > 4 {
return true
}
if v1 == 1 && v2 == 4 && v3 >= 20 {
return true
}
return false
}
// Checks if an iptablse version is after 1.6.0, when --wait support second
func iptablesWaitSupportSecond(v1 int, v2 int) bool {
if v1 > 1 {
return true
}
if v1 == 1 && v2 >= 6 {
return true
}
return false
}
// Checks if an iptables version is after 1.6.2, when --random-fully was added
func iptablesHasRandomFully(v1 int, v2 int, v3 int) bool {
if v1 > 1 {
return true
}
if v1 == 1 && v2 > 6 {
return true
}
if v1 == 1 && v2 == 6 && v3 >= 2 {
return true
}
return false
}
// Checks if a rule specification exists for a table
func (ipt *IPTables) existsForOldIptables(table, chain string, rulespec []string) (bool, error) {
rs := strings.Join(append([]string{"-A", chain}, rulespec...), " ")
args := []string{"-t", table, "-S"}
var stdout bytes.Buffer
err := ipt.runWithOutput(args, &stdout)
if err != nil {
return false, err
}
return strings.Contains(stdout.String(), rs), nil
}
// counterRegex is the regex used to detect nftables counter format
var counterRegex = regexp.MustCompile(`^\[([0-9]+):([0-9]+)\] `)
// filterRuleOutput works around some inconsistencies in output.
// For example, when iptables is in legacy vs. nftables mode, it produces
// different results.
func filterRuleOutput(rule string) string {
out := rule
// work around an output difference in nftables mode where counters
// are output in iptables-save format, rather than iptables -S format
// The string begins with "[0:0]"
//
// Fixes #49
if groups := counterRegex.FindStringSubmatch(out); groups != nil {
// drop the brackets
out = out[len(groups[0]):]
out = fmt.Sprintf("%s -c %s %s", out, groups[1], groups[2])
}
return out
}
func GetIPTablesRuleSpecification(rule, specification string) string {
parts := strings.Split(rule, " ")
for i, part := range parts {
if part == specification && i+1 < len(parts) {
return parts[i+1]
}
}
return ""
}

84
pkg/iptables/lock.go Normal file
View File

@@ -0,0 +1,84 @@
// Copyright 2015 CoreOS, Inc.
//
// 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 iptables
import (
"os"
"sync"
"syscall"
)
const (
// In earlier versions of iptables, the xtables lock was implemented
// via a Unix socket, but now flock is used via this lockfile:
// http://git.netfilter.org/iptables/commit/?id=aa562a660d1555b13cffbac1e744033e91f82707
// Note the LSB-conforming "/run" directory does not exist on old
// distributions, so assume "/var" is symlinked
xtablesLockFilePath = "/var/run/xtables.lock"
defaultFilePerm = 0600
)
type Unlocker interface {
Unlock() error
}
type nopUnlocker struct{}
func (n nopUnlocker) Unlock() error { return nil }
type fileLock struct {
// mu is used to protect against concurrent invocations from within this process
mu sync.Mutex
fd int
}
// tryLock takes an exclusive lock on the xtables lock file without blocking.
// This is best-effort only: if the exclusive lock would block (i.e. because
// another process already holds it), no error is returned. Otherwise, any
// error encountered during the locking operation is returned.
// The returned Unlocker should be used to release the lock when the caller is
// done invoking iptables commands.
func (l *fileLock) tryLock() (Unlocker, error) {
l.mu.Lock()
err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB)
switch err {
case syscall.EWOULDBLOCK:
l.mu.Unlock()
return nopUnlocker{}, nil
case nil:
return l, nil
default:
l.mu.Unlock()
return nil, err
}
}
// Unlock closes the underlying file, which implicitly unlocks it as well. It
// also unlocks the associated mutex.
func (l *fileLock) Unlock() error {
defer l.mu.Unlock()
return syscall.Close(l.fd)
}
// newXtablesFileLock opens a new lock on the xtables lockfile without
// acquiring the lock
func newXtablesFileLock() (*fileLock, error) {
fd, err := syscall.Open(xtablesLockFilePath, os.O_CREATE, defaultFilePerm)
if err != nil {
return nil, err
}
return &fileLock{fd: fd}, nil
}

91
pkg/iptables/version.go Normal file
View File

@@ -0,0 +1,91 @@
package iptables
import (
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
)
type Version struct {
Major int
Minor int
Patch int
BackendMode string
}
func (v Version) String() string {
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
func (v Version) Compare(other Version) int {
if v.Major != other.Major {
return v.Major - other.Major
}
if v.Minor != other.Minor {
return v.Minor - other.Minor
}
return v.Patch - other.Patch
}
func ParseVersion(versionString string) (Version, error) {
re := regexp.MustCompile(`v([0-9]+)\.([0-9]+)\.([0-9]+)`)
match := re.FindStringSubmatch(versionString)
if len(match) != 4 {
return Version{}, fmt.Errorf("invalid version string: %s", versionString)
}
major, _ := strconv.Atoi(match[1])
minor, _ := strconv.Atoi(match[2])
patch, _ := strconv.Atoi(match[3])
return Version{Major: major, Minor: minor, Patch: patch}, nil
}
func GetVersion() (Version, error) {
ver := Version{}
cmd := exec.Command("iptables", "--version")
out, err := cmd.Output()
if err != nil {
return ver, fmt.Errorf("run cmd 'iptables --version' wtith error: %v", err)
}
ver, err = ParseVersion(string(out))
if err != nil {
return ver, err
}
nft4 := getOutput("iptables-nft-save")
legacy4 := getOutput("iptables-legacy-save")
nft6 := getOutput("ip6tables-nft-save")
legacy6 := getOutput("ip6tables-legacy-save")
if strings.Contains(nft4, "KUBE-IPTABLES") ||
strings.Contains(nft6, "KUBE-IPTABLES") ||
strings.Contains(nft4, "KUBE-KUBELET") ||
strings.Contains(nft6, "KUBE-KUBELET") {
ver.BackendMode = "nft"
} else if strings.Contains(legacy4, "KUBE-IPTABLES") ||
strings.Contains(legacy6, "KUBE-IPTABLES") ||
strings.Contains(legacy4, "KUBE-KUBELET") ||
strings.Contains(legacy6, "KUBE-KUBELET") {
ver.BackendMode = "legacy"
} else {
nftCount := strings.Count(nft4, "\n") + strings.Count(nft6, "\n")
legacyCount := strings.Count(legacy4, "\n") + strings.Count(legacy6, "\n")
if nftCount >= legacyCount {
ver.BackendMode = "nft"
} else {
ver.BackendMode = "legacy"
}
}
return ver, nil
}
func getOutput(name string) string {
cmd := exec.Command(name)
out, _ := cmd.Output()
return string(out)
}

123
pkg/k8s/client.go Normal file
View File

@@ -0,0 +1,123 @@
package k8s
import (
"crypto/tls"
"fmt"
"net"
"time"
log "log/slog"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
const (
defaultTimeout = 10 * time.Second
)
// NewClientset takes REST config and returns k8s clientest.
func NewClientset(config *rest.Config) (*kubernetes.Clientset, error) {
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error())
}
return clientset, nil
}
// NewRestConfig takes an optional configPath and creates a new REST config for clientset.
// If the configPath is not specified, and inCluster is true, then an
// InClusterConfig is used.
// Also takes a hostname which allow for overriding the config's hostname.
func NewRestConfig(configPath string, inCluster bool, hostname string) (*rest.Config, error) {
config, err := restConfig(configPath, inCluster, defaultTimeout)
if err != nil {
return nil, fmt.Errorf("failed to create rest config: %w", err)
}
if len(hostname) > 0 {
config.Host = hostname
}
return config, nil
}
func restConfig(kubeconfig string, inCluster bool, timeout time.Duration) (*rest.Config, error) {
var cfg *rest.Config
var err error
if inCluster {
if cfg, err = rest.InClusterConfig(); err != nil {
return nil, fmt.Errorf("failed to get incluster config: %w", err)
}
} else if kubeconfig != "" {
if cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfig); err != nil {
return nil, fmt.Errorf("failed to build config from file '%s': %w", kubeconfig, err)
}
} else {
return nil, fmt.Errorf("failed to build config from file: path to KubeConfig not specified")
}
// Override some of the defaults allowing a little bit more flexibility speaking with the API server
// these should hopefully be redundant, however issues will still be logged.
cfg.QPS = 100
cfg.Burst = 250
cfg.Timeout = timeout
return cfg, nil
}
func findAddressFromRemoteCert(address string) ([]net.IP, error) {
// TODO: should we care at this point, probably not as we just want the certificates
conf := &tls.Config{
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: true, //nolint
}
d := &net.Dialer{
Timeout: time.Duration(3) * time.Second,
}
// Create the TCP connection
conn, err := tls.DialWithDialer(d, "tcp", address, conf)
if err != nil {
return nil, err
}
defer conn.Close()
// Grab the certificactes
certs := conn.ConnectionState().PeerCertificates
if len(certs) > 1 {
return nil, fmt.Errorf("[k8s client] not designed to recive multiple certs from API server")
}
return certs[0].IPAddresses, nil
}
func FindWorkingKubernetesAddress(configPath string, inCluster bool) (*rest.Config, error) {
// check with loopback, and retrieve its certificate
ips, err := findAddressFromRemoteCert("127.0.0.1:6443")
if err != nil {
return nil, err
}
for x := range ips {
log.Debug("[k8s client] testing", "address", ips[x].String())
c, err := NewRestConfig(configPath, inCluster, net.JoinHostPort(ips[x].String(), "6443"))
if err != nil {
log.Error("failed to create k8s REST config", "err", err)
}
c.Timeout = 2 * time.Second
k, err := NewClientset(c)
if err != nil {
log.Error("failed to create k8s clientset", "err", err)
}
_, err = k.DiscoveryClient.ServerVersion()
if err == nil {
log.Info("[k8s client] working", "address", ips[x].String())
c.Timeout = defaultTimeout
return c, nil
}
}
return nil, fmt.Errorf("unable to find a working address for the local API server [%v]", err)
}

70
pkg/k8s/client_test.go Normal file
View File

@@ -0,0 +1,70 @@
package k8s
//"192.168.0.174:6443"
// func Test_findAddressFromRemoteCert(t *testing.T) {
// type args struct {
// address string
// }
// tests := []struct {
// name string
// args args
// want []net.IP
// wantErr bool
// }{
// {
// name: "test server",
// args: args{address: "192.168.0.174:6443"},
// want: []net.IP{net.IPv4(10, 96, 0, 1), net.IPv4(192, 168, 0, 174)},
// wantErr: false,
// },
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// got, err := findAddressFromRemoteCert(tt.args.address)
// if (err != nil) != tt.wantErr {
// t.Errorf("findAddressFromRemoteCert() error = %v, wantErr %v", err, tt.wantErr)
// return
// }
// if !reflect.DeepEqual(got, tt.want) {
// t.Errorf("findAddressFromRemoteCert() = %v, want %v", got, tt.want)
// }
// })
// }
// }
// //findAddressFromRemoteCert() =
// //[10.96.0.1 192.168.0.174]
// //[10.96.0.1 192.168.0.174]
// func Test_findWorkingKubernetesAddress(t *testing.T) {
// type args struct {
// configPath string
// inCluster bool
// }
// tests := []struct {
// name string
// args args
// want *kubernetes.Clientset
// wantErr bool
// }{
// {
// name: "test",
// args: args{
// configPath: "/home/dan/super-admin.conf",
// inCluster: false,
// },
// wantErr: false,
// },
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// _, err := FindWorkingKubernetesAddress(tt.args.configPath, tt.args.inCluster)
// if (err != nil) != tt.wantErr {
// t.Errorf("findWorkingKubernetesAddress() error = %v, wantErr %v", err, tt.wantErr)
// return
// }
// })
// }
// }

View File

@@ -0,0 +1,49 @@
package kubevip
const (
// Hardware address of the host that has the VIP
HwAddrKey = "kube-vip.io/hwaddr"
// The IP address that is requested
RequestedIP = "kube-vip.io/requestedIP"
// The host that has the VIP
VipHost = "kube-vip.io/vipHost"
// Enable Egress on a service
Egress = "kube-vip.io/egress"
// Enable internal Egress
EgressInternal = "kube-vip.io/egress-internal"
// Egress should be IPv6
EgressIPv6 = "kube-vip.io/egress-ipv6"
// Ports that traffic is allowed to access from the egress VIP
EgressDestinationPorts = "kube-vip.io/egress-destination-ports"
// Allowed incoming ports to the VIP
EgressSourcePorts = "kube-vip.io/egress-source-ports"
// Allowed networks for the Egress to be enabled for
EgressAllowedNetworks = "kube-vip.io/egress-allowed-networks"
// Networks that we wont Egress for
EgressDeniedNetworks = "kube-vip.io/egress-denied-networks"
// The current active endpoint(pod) for the Egress VIP
ActiveEndpoint = "kube-vip.io/active-endpoint"
// The current active endpoint(pod) for the Egress VIP (v6)
ActiveEndpointIPv6 = "kube-vip.io/active-endpoint-ipv6"
// Flush the conntrack rules (remove existing sessions) once Egress is configured
FlushContrack = "kube-vip.io/flush-conntrack"
LoadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs"
LoadbalancerHostname = "kube-vip.io/loadbalancerHostname"
ServiceInterface = "kube-vip.io/serviceInterface"
UpnpEnabled = "kube-vip.io/forwardUPNP"
RPFilter = "kube-vip.io/rp_filter" // Set the return path filter for a specific service interface
)

View File

@@ -1,71 +0,0 @@
package kubevip
import (
"fmt"
"net/url"
"strconv"
log "github.com/sirupsen/logrus"
)
func init() {
// Start the index negative as it will be incrememnted of first approach
endPointIndex = -1
}
// ValidateBackEndURLS will run through the endpoints and ensure that they're a valid URL
func ValidateBackEndURLS(endpoints *[]BackEnd) error {
for i := range *endpoints {
log.Debugf("Parsing [%s]", (*endpoints)[i].RawURL)
u, err := url.Parse((*endpoints)[i].RawURL)
if err != nil {
return err
}
// No error is returned if the prefix/schema is missing
// If the Host is empty then we were unable to parse correctly (could be prefix is missing)
if u.Host == "" {
return fmt.Errorf("Unable to parse [%s], ensure it's prefixed with http(s)://", (*endpoints)[i].RawURL)
}
(*endpoints)[i].Address = u.Hostname()
// if a port is specified then update the internal endpoint stuct, if not rely on the schema
if u.Port() != "" {
portNum, err := strconv.Atoi(u.Port())
if err != nil {
return err
}
(*endpoints)[i].Port = portNum
}
(*endpoints)[i].ParsedURL = u
}
return nil
}
// ReturnEndpointAddr - returns an endpoint
func (lb LoadBalancer) ReturnEndpointAddr() (string, error) {
if len(lb.Backends) == 0 {
return "", fmt.Errorf("No Backends configured")
}
if endPointIndex < len(lb.Backends)-1 {
endPointIndex++
} else {
// reset the index to the beginning
endPointIndex = 0
}
// TODO - weighting, decision algorythmn
return fmt.Sprintf("%s:%d", lb.Backends[endPointIndex].Address, lb.Backends[endPointIndex].Port), nil
}
// ReturnEndpointURL - returns an endpoint
func (lb LoadBalancer) ReturnEndpointURL() *url.URL {
if endPointIndex != len(lb.Backends)-1 {
endPointIndex++
} else {
// reset the index to the beginning
endPointIndex = 0
}
// TODO - weighting, decision algorythmn
return lb.Backends[endPointIndex].ParsedURL
}

View File

@@ -0,0 +1,671 @@
package kubevip
import (
"encoding/json"
"fmt"
"math"
"math/bits"
"os"
"strconv"
"strings"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/detector"
)
// ParseEnvironment - will popultate the configuration from environment variables
func ParseEnvironment(c *Config) error {
if c == nil {
return nil
}
// Ensure that logging is set through the environment variables
env := os.Getenv(vipLogLevel)
if env != "" {
logLevel, err := strconv.ParseInt(env, 10, 32)
if err != nil {
panic("Unable to parse environment variable [vip_loglevel], should be int")
}
c.Logging = int32(logLevel)
}
// Find interface
env = os.Getenv(vipInterface)
if env != "" {
c.Interface = env
}
env = os.Getenv(vipInterfaceLoGlobal)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.LoInterfaceGlobalScope = b
}
// Find (services) interface
env = os.Getenv(vipServicesInterface)
if env != "" {
c.ServicesInterface = env
}
// Find Kubernetes Leader Election configuration
env = os.Getenv(vipLeaderElection)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableLeaderElection = b
}
// Attempt to find the Lease name from the environment variables
env = os.Getenv(vipLeaseName)
if env != "" {
c.LeaseName = env
}
// Attempt to find the Lease configuration from the environment variables
env = os.Getenv(vipLeaseDuration)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.LeaseDuration = int(i)
}
env = os.Getenv(vipRenewDeadline)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.RenewDeadline = int(i)
}
env = os.Getenv(vipRetryPeriod)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.RetryPeriod = int(i)
}
// Attempt to find the Lease annotations from the environment variables
env = os.Getenv(vipLeaseAnnotations)
if env != "" {
err := json.Unmarshal([]byte(env), &c.LeaseAnnotations)
if err != nil {
return err
}
}
env = os.Getenv(nodeName)
if env != "" {
c.NodeName = env
}
// Find vip address
env = os.Getenv(vipAddress)
if env != "" {
// TODO - parse address net.Host()
c.VIP = env
// } else {
// c.VIP = os.Getenv(address)
}
// Find address
env = os.Getenv(address)
if env != "" {
// TODO - parse address net.Host()
c.Address = env
}
// Find vip port
env = os.Getenv(port)
if env != "" {
i, err := strconv.ParseUint(env, 10, 16)
if err != nil {
return err
}
c.Port = uint16(i)
}
// Find vipDdns
env = os.Getenv(vipDdns)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.DDNS = b
}
// Find the namespace that the control plane should use (for leaderElection lock)
env = os.Getenv(cpNamespace)
if env != "" {
c.Namespace = env
}
// Find controlplane toggle
env = os.Getenv(cpEnable)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableControlPlane = b
}
// Find controlplane toggle
env = os.Getenv(cpDetect)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.DetectControlPlane = b
}
env = os.Getenv(kubernetesAddr)
if env != "" {
c.KubernetesAddr = env
}
// Find Services toggle
env = os.Getenv(svcEnable)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableServices = b
// Find Services leader Election
env = os.Getenv(svcElection)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableServicesElection = b
}
// Find load-balancer class only
env = os.Getenv(lbClassOnly)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.LoadBalancerClassOnly = b
}
// Load-balancer class name
env, exists := os.LookupEnv(lbClassName)
if exists {
c.LoadBalancerClassName = env
}
// Load-balancer class legacy handling
env = os.Getenv(lbClassLegacyHandling)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.LoadBalancerClassLegacyHandling = b
}
// Find the namespace that the control plane should use (for leaderElection lock)
env = os.Getenv(svcNamespace)
if env != "" {
c.ServiceNamespace = env
}
// Gets the leaseName for services in arp mode
env = os.Getenv(svcLeaseName)
if env != "" {
c.ServicesLeaseName = env
}
}
// Find vip address subnet
env = os.Getenv(vipSubnet)
if env != "" {
c.VIPSubnet = env
}
// Find Single Node
env = os.Getenv(vipSingleNode)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.SingleNode = b
}
// Find annotation configuration
env = os.Getenv(annotations)
if env != "" {
c.Annotations = env
}
// Find Start As Leader
// TODO - does this need deprecating?
// Required when the host sets itself as leader before the state change
env = os.Getenv(vipStartLeader)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.StartAsLeader = b
}
// Find if ARP is enabled
env = os.Getenv(vipArp)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableARP = b
}
// Find if ARP is enabled
env = os.Getenv(vipArpRate)
if env != "" {
i64, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.ArpBroadcastRate = i64
} else {
// default to three seconds
c.ArpBroadcastRate = 3000
}
// Wireguard Mode
env = os.Getenv(vipWireguard)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableWireguard = b
}
// Routing Table Mode
env = os.Getenv(vipRoutingTable)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableRoutingTable = b
}
// Routing Table ID
env = os.Getenv(vipRoutingTableID)
if env != "" {
i, err := strconv.ParseInt(env, 10, 64)
if err != nil {
return err
}
if i >= 0 && i <= math.MaxInt {
c.RoutingTableID = int(i)
} else if i < 0 {
return fmt.Errorf("no support of negative [%d] in env var %q", i, vipRoutingTableID)
} else {
// +1 for the signing bit as it is 0 for positive integers
return fmt.Errorf("no support for int64, system natively supports [int%d]", bits.OnesCount(math.MaxInt)+1)
}
}
// Routing Table Type
env = os.Getenv(vipRoutingTableType)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.RoutingTableType = int(i)
}
// Routing protocol
env = os.Getenv(vipRoutingProtocol)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.RoutingProtocol = int(i)
}
// Clean routing table
env = os.Getenv(vipCleanRoutingTable)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.CleanRoutingTable = b
}
// DNS mode
env = os.Getenv(dnsMode)
if env != "" {
c.DNSMode = env
}
// Disable updates for services (status.LoadBalancer.Ingress will not be updated)
env = os.Getenv(disableServiceUpdates)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.DisableServiceUpdates = b
}
// BGP Server options
env = os.Getenv(bgpEnable)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableBGP = b
}
// BGP Router interface determines an interface that we can use to find an address for
env = os.Getenv(bgpRouterInterface)
if env != "" {
_, address, err := detector.FindIPAddress(env)
if err != nil {
return err
}
c.BGPConfig.RouterID = address
}
// RouterID
env = os.Getenv(bgpRouterID)
if env != "" {
c.BGPConfig.RouterID = env
}
// AS
env = os.Getenv(bgpRouterAS)
if env != "" {
u64, err := strconv.ParseUint(env, 10, 32)
if err != nil {
return err
}
c.BGPConfig.AS = uint32(u64)
}
// Peer AS
env = os.Getenv(bgpPeerAS)
if env != "" {
u64, err := strconv.ParseUint(env, 10, 32)
if err != nil {
return err
}
c.BGPPeerConfig.AS = uint32(u64)
}
// Peer AS
env = os.Getenv(bgpPeers)
if env != "" {
peers, err := bgp.ParseBGPPeerConfig(env)
if err != nil {
return err
}
c.BGPConfig.Peers = peers
}
// MPBGP mode
env = os.Getenv(mpbgpNexthop)
if env != "" {
c.BGPConfig.MpbgpNexthop = env
}
// MPBGP fixed IPv4
env = os.Getenv(mpbgpIPv4)
if env != "" {
c.BGPConfig.MpbgpIPv4 = env
}
// MPBGP fixed IPv6
env = os.Getenv(mpbgpIPv6)
if env != "" {
c.BGPConfig.MpbgpIPv6 = env
}
// BGP Peer mutlihop
env = os.Getenv(bgpMultiHop)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.BGPPeerConfig.MultiHop = b
}
// BGP Peer password
env = os.Getenv(bgpPeerPassword)
if env != "" {
c.BGPPeerConfig.Password = env
}
// BGP Source Interface
env = os.Getenv(bgpSourceIF)
if env != "" {
c.BGPConfig.SourceIF = env
}
// BGP Source Address
env = os.Getenv(bgpSourceIP)
if env != "" {
c.BGPConfig.SourceIP = env
}
// BGP Peer options, add them if relevant
env = os.Getenv(bgpPeerAddress)
if env != "" {
c.BGPPeerConfig.Address = env
// If we've added in a peer configuration, then we should add it to the BGP configuration
c.BGPConfig.Peers = append(c.BGPConfig.Peers, c.BGPPeerConfig)
}
// BGP Timers options
env = os.Getenv(bgpHoldTime)
if env != "" {
u64, err := strconv.ParseUint(env, 10, 32)
if err != nil {
return err
}
c.BGPConfig.HoldTime = u64
}
env = os.Getenv(bgpKeepaliveInterval)
if env != "" {
u64, err := strconv.ParseUint(env, 10, 32)
if err != nil {
return err
}
c.BGPConfig.KeepaliveInterval = u64
}
env = os.Getenv(zebraEnable)
if env != "" {
result, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.BGPConfig.Zebra.Enabled = result
}
env = os.Getenv(zebraURL)
if env != "" {
c.BGPConfig.Zebra.URL = env
}
env = os.Getenv(zebraVersion)
if env != "" {
u64, err := strconv.ParseUint(env, 10, 32)
if err != nil {
return err
}
c.BGPConfig.Zebra.Version = uint32(u64)
}
env = os.Getenv(zebraSoftwareName)
if env != "" {
c.BGPConfig.Zebra.SoftwareName = env
}
// Enable the load-balancer
env = os.Getenv(lbEnable)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableLoadBalancer = b
}
// Find loadbalancer port
env = os.Getenv(lbPort)
if env != "" {
i, err := strconv.ParseUint(env, 10, 16)
if err != nil {
return err
}
c.LoadBalancerPort = uint16(i)
}
// Find loadbalancer forwarding method
env = os.Getenv(lbForwardingMethod)
if env != "" {
c.LoadBalancerForwardingMethod = env
}
env = os.Getenv(EnableServiceSecurity)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableServiceSecurity = b
}
// Find if node labeling is enabled
env = os.Getenv(EnableNodeLabeling)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableNodeLabeling = b
}
// Find Prometheus configuration
env = os.Getenv(prometheusServer)
if env != "" {
c.PrometheusHTTPServer = env
}
// Set Egress configuration(s)
env = os.Getenv(egressPodCidr)
if env != "" {
c.EgressPodCidr = env
}
env = os.Getenv(egressServiceCidr)
if env != "" {
c.EgressServiceCidr = env
}
// if this is set then we're enabling nftables
env = os.Getenv(egressWithNftables)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EgressWithNftables = b
}
// check to see if we're using a specific path to the Kubernetes config file
env = os.Getenv(k8sConfigFile)
if env != "" {
c.K8sConfigFile = env
}
env = os.Getenv(enableEndpoints)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableEndpoints = b
}
env = os.Getenv(mirrorDestInterface)
if env != "" {
c.MirrorDestInterface = env
}
env = os.Getenv(iptablesBackend)
if env != "" {
c.IptablesBackend = env
}
env = os.Getenv(backendHealthCheckInterval)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
c.BackendHealthCheckInterval = int(i)
}
env = os.Getenv(healthCheckPort)
if env != "" {
i, err := strconv.ParseInt(env, 10, 32)
if err != nil {
return err
}
if i < 1024 {
return fmt.Errorf("health check port should be > 1024")
}
c.HealthCheckPort = int(i)
}
env = os.Getenv(enableUPNP)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EnableUPNP = b
}
if env = os.Getenv(egressClean); env == "" {
env = os.Getenv(strings.ToUpper(egressClean))
}
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.EgressClean = b
}
return nil
}

View File

@@ -0,0 +1,237 @@
package kubevip
// Environment variables
const (
// vipArp - defines if the arp broadcast should be enabled
vipArp = "vip_arp"
// vip_arpRate - defines the rate of gARP broadcasts
vipArpRate = "vip_arpRate"
// vipLeaderElection - defines if the kubernetes algorithm should be used
vipLeaderElection = "vip_leaderelection"
// vipLeaseName - defines the name of the lease lock
vipLeaseName = "vip_leasename"
// vipLeaderElection - defines if the kubernetes algorithm should be used
vipLeaseDuration = "vip_leaseduration"
// vipLeaderElection - defines if the kubernetes algorithm should be used
vipRenewDeadline = "vip_renewdeadline"
// vipLeaderElection - defines if the kubernetes algorithm should be used
vipRetryPeriod = "vip_retryperiod"
// vipLeaderElection - defines the annotations given to the lease lock
vipLeaseAnnotations = "vip_leaseannotations"
// vipLogLevel - defines the level of logging to produce (5 being the most verbose)
vipLogLevel = "vip_loglevel"
// vipInterface - defines the interface that the vip should bind too
vipInterface = "vip_interface"
// vipInterfaceLoGlobal - defines if the lo interface (if used) should have a global scope
vipInterfaceLoGlobal = "vip_interfaceloglobal"
// vipServicesInterface - defines the interface that the service vips should bind too
vipServicesInterface = "vip_servicesinterface"
// vipSubnet - defines the subnet that the vip will use
vipSubnet = "vip_subnet"
// egressPodCidr - defines the cidr that egress will ignore
egressPodCidr = "egress_podcidr"
// egressServiceCidr - defines the cidr that egress will ignore
egressServiceCidr = "egress_servicecidr"
// egressWithNftables - enables using nftables over iptables
egressWithNftables = "egress_withnftables"
/////////////////////////////////////
// TO DO:
// Determine how to tidy this mess up
/////////////////////////////////////
// vipAddress - defines the address that the vip will expose
// DEPRECATED: will be removed in a next release
vipAddress = "vip_address"
// address - defines the address that would be used as a vip
// it may be an IP or a DNS name, in case of a DNS name
// kube-vip will try to resolve it and use the IP as a VIP
address = "address"
// port - defines the port for the VIP
port = "port"
// annotations
annotations = "annotation"
// vipDdns - defines if use dynamic dns to allocate IP for "address"
vipDdns = "vip_ddns"
// vipLeaseNodeName defines the node name that is used to acquire leases
nodeName = "vip_nodename"
// vipSingleNode - defines the vip start as a single node cluster
vipSingleNode = "vip_singlenode"
// vipStartLeader - will start this instance as the leader of the cluster
vipStartLeader = "vip_startleader"
// bgpEnable defines if BGP should be enabled
bgpEnable = "bgp_enable"
// bgpRouterID defines the routerID for the BGP server
bgpRouterID = "bgp_routerid"
// bgpRouterInterface defines the interface that we can find the address for
bgpRouterInterface = "bgp_routerinterface"
// bgpRouterAS defines the AS for the BGP server
bgpRouterAS = "bgp_as"
// bgpPeerAddress defines the address for a BGP peer
bgpPeerAddress = "bgp_peeraddress"
// bgpPeers defines the address for a BGP peer
bgpPeers = "bgp_peers"
// bgpPeerAS defines the AS for a BGP peer
bgpPeerAS = "bgp_peeras"
// bgpPeerAS defines the AS for a BGP peer
bgpPeerPassword = "bgp_peerpass" // nolint
// bgpMultiHop enables mulithop routing
bgpMultiHop = "bgp_multihop"
// bgpSourceIF defines the source interface for BGP peering
bgpSourceIF = "bgp_sourceif"
// bgpSourceIP defines the source address for BGP peering
bgpSourceIP = "bgp_sourceip"
// bgpHoldTime defines bgp timers hold time
bgpHoldTime = "bgp_hold_time"
// bgpKeepaliveInterval defines bgp timers keepalive interval
bgpKeepaliveInterval = "bgp_keepalive_interval"
// zebraEnable defines if Zebra integraton should be enabled
zebraEnable = "zebra_enable"
// zebraUrl specifies path to the unix domain socket for connecting to Zebra daemon
zebraURL = "zebra_url"
// zebraVersion specifies Zebra API Version
zebraVersion = "zebra_version"
// zebraSoftwareName specifies Software Name for Zebra
zebraSoftwareName = "zebra_software_name"
// mpbgpNexthop defines MPBGP mode
mpbgpNexthop = "mpbgp_nexthop"
// mpbgpIPv4 defines fixed IPv4 to be used with MPBGP
mpbgpIPv4 = "mpbgp_ipv4"
// mpbgpIPv6 defines fixed IPv6 to be used with MPBGP
mpbgpIPv6 = "mpbgp_ipv6"
// vipWireguard - defines if wireguard will be used for vips
vipWireguard = "vip_wireguard" //nolint
// vipRoutingTable - defines if table mode will be used for vips
vipRoutingTable = "vip_routingtable" //nolint
// vipRoutingTableID - defines which table mode will be used for vips
vipRoutingTableID = "vip_routingtableid" //nolint
// vipRoutingTableType - defines which table type will be used for vip routes
// valid values for this variable can be found in:
// https://pkg.go.dev/golang.org/x/sys/unix#RTN_UNSPEC
// Note that route type have the prefix `RTN_`, and you
// specify the integer value, not the name. For example:
// you should say `vip_routingtabletype=2` for RTN_LOCAL
vipRoutingTableType = "vip_routingtabletype" //nolint
// vipRoutingProtocol - defines what value will be used as protocol when creating routes
vipRoutingProtocol = "vip_routingprotocol" //nolint
// vipCleanRoutingTable - defines if routing table will be cleaned of redundant routes on kube-vip's start
vipCleanRoutingTable = "vip_cleanroutingtable" //nolint
// cpNamespace defines the namespace the control plane pods will run in
cpNamespace = "cp_namespace"
// cpEnable enables the control plane feature
cpEnable = "cp_enable"
// cpDetect will attempt to automatically find a working address for the control plane from loopback
cpDetect = "cp_detect"
// kubernetesAddris the address of the Kubernetes API server on this machine
kubernetesAddr = "kubernetes_addr"
// svcEnable enables the Kubernetes service feature
svcEnable = "svc_enable"
// svcNamespace defines the namespace the service pods will run in
svcNamespace = "svc_namespace"
// svcElection enables election per Kubernetes service
svcElection = "svc_election"
// svcLeaseName Name of the lease that is used for leader election for services (in arp mode)
svcLeaseName = "svc_leasename"
// lbClassOnly enables load-balancer for class "kube-vip.io/kube-vip-class" only
lbClassOnly = "lb_class_only"
// lbClassName enables load-balancer for a specific class only
lbClassName = "lb_class_name"
// lbClassLegacyHandling enables legacy handing of load-balancer class
lbClassLegacyHandling = "lb_class_legacy_handling"
// lbEnable defines if the load-balancer should be enabled
lbEnable = "lb_enable"
// lbPort defines the port of load-balancer
lbPort = "lb_port"
// lbForwardingMethod defines the forwarding method of load-balancer
lbForwardingMethod = "lb_fwdmethod"
// EnableServiceSecurity defines if the load-balancer should only allow traffic to service ports
EnableServiceSecurity = "enable_service_security"
// EnableNodeLabeling, will enable node labeling as the node becomes leader
EnableNodeLabeling = "enable_node_labeling"
// prometheusServer defines the address prometheus listens on
prometheusServer = "prometheus_server"
// vipConfigMap defines the configmap that kube-vip will watch for service definitions
// vipConfigMap = "vip_configmap"
// k8sConfigFile defines the path to the configfile used to speak with the API server
k8sConfigFile = "k8s_config_file"
// dnsMode defines mode that DNS lookup will be performed with (first, ipv4, ipv6, dual)
dnsMode = "dns_mode"
// disableServiceUpdates disables service updating
disableServiceUpdates = "disable_service_updates"
// enableEndpoints enables use of Endpoints instead of EndpointSlices
enableEndpoints = "enable_endpoints"
// mirrorDestInterface is the network interface where all traffics that go through service interface
// will be mirrored to. The source interface is ServicesInterface by default, fall back to Interface if not set.
// + optional
mirrorDestInterface = "mirror_dest_interface"
// iptablesBackend iptables backend, can be specified as `nft` or `legacy`. If not set, it defaults to automatic detection.
iptablesBackend = "iptables_backend"
// backendHealthCheckInterval Interval in seconds for checking backend health.
backendHealthCheckInterval = "backend_health_check_interval"
// healthCheckPort, if set to non-zero will be the port the health check will listen on
healthCheckPort = "health_check_port"
// enableUPNP enables UPNP functions
enableUPNP = "enable_upnp"
// egressClean enables egress cleaning on kube-vip's start
egressClean = "egress_clean"
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
package kubevip
import "testing"
func TestParseEnvironment(t *testing.T) {
tests := []struct {
name string
c *Config
wantErr bool
}{
{"", nil, false},
{"", &Config{Interface: "eth0", ServicesInterface: "eth1"}, false},
}
for _, tt := range tests {
t.Logf("%v", tt.c)
t.Run(tt.name, func(t *testing.T) {
if err := ParseEnvironment(tt.c); (err != nil) != tt.wantErr {
t.Errorf("ParseEnvironment() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@@ -2,182 +2,56 @@ package kubevip
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"github.com/ghodss/yaml"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/vishvananda/netlink"
)
var endPointIndex int // Holds the previous endpoint (for determining decisions on next endpoint)
const (
Auto = "auto"
)
//ParseBackendConfig -
func ParseBackendConfig(ep string) (*BackEnd, error) {
endpoint := strings.Split(ep, ":")
if len(endpoint) != 2 {
return nil, fmt.Errorf("Ensure a backend is in in the format address:port, e.g. 10.0.0.1:8080")
}
p, err := strconv.Atoi(endpoint[1])
if err != nil {
return nil, err
}
return &BackEnd{Address: endpoint[0], Port: p}, nil
}
//ParsePeerConfig -
func ParsePeerConfig(ep string) (*RaftPeer, error) {
endpoint := strings.Split(ep, ":")
if len(endpoint) != 3 {
return nil, fmt.Errorf("Ensure a peer is in in the format id:address:port, e.g. server1:10.0.0.1:8080")
}
p, err := strconv.Atoi(endpoint[2])
if err != nil {
return nil, err
}
return &RaftPeer{ID: endpoint[0], Address: endpoint[1], Port: p}, nil
}
//OpenConfig will attempt to read a file and parse it's contents into a configuration
func OpenConfig(path string) (*Config, error) {
if path == "" {
return nil, fmt.Errorf("Path cannot be blank")
}
log.Infof("Reading configuration from [%s]", path)
// Check the actual path from the string
if _, err := os.Stat(path); !os.IsNotExist(err) {
// Attempt to read the data
configData, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
func (c *Config) CheckInterface() error {
if c.Interface != "" {
if err := isValidInterface(c.Interface); err != nil {
return fmt.Errorf("%s is not valid interface, reason: %w", c.Interface, err)
}
// If data is read succesfully parse the yaml
var c Config
err = yaml.Unmarshal(configData, &c)
if err != nil {
return nil, err
}
return &c, nil
}
return nil, fmt.Errorf("Error reading [%s]", path)
}
//PrintConfig - will print out an instance of the kubevip config
func (c *Config) PrintConfig() {
b, _ := yaml.Marshal(c)
fmt.Printf(string(b))
}
//ParseFlags will write the current configuration to a specified [path]
func (c *Config) ParseFlags(localPeer string, remotePeers, backends []string) error {
// Parse localPeer
p, err := ParsePeerConfig(localPeer)
if err != nil {
return err
}
c.LocalPeer = *p
// Parse remotePeers
//Iterate backends
for i := range remotePeers {
p, err := ParsePeerConfig(remotePeers[i])
if err != nil {
return err
}
c.RemotePeers = append(c.RemotePeers, *p)
}
//Iterate backends
for i := range backends {
b, err := ParseBackendConfig(backends[i])
if err != nil {
return err
if c.ServicesInterface != "" {
if err := isValidInterface(c.ServicesInterface); err != nil {
return fmt.Errorf("%s is not valid interface, reason: %w", c.ServicesInterface, err)
}
c.LoadBalancers[0].Backends = append(c.LoadBalancers[0].Backends, *b)
}
return nil
}
//SampleConfig will create an example configuration and write it to the specified [path]
func SampleConfig() {
// Generate Sample configuration
c := &Config{
// Generate sample peers
RemotePeers: []RaftPeer{
{
ID: "server2",
Address: "192.168.0.2",
Port: 10000,
},
{
ID: "server3",
Address: "192.168.0.3",
Port: 10000,
},
},
LocalPeer: RaftPeer{
ID: "server1",
Address: "192.168.0.1",
Port: 10000,
},
// Virtual IP address
VIP: "192.168.0.100",
// Interface to bind to
Interface: "eth0",
// Load Balancer Configuration
LoadBalancers: []LoadBalancer{
{
Name: "Kubernetes Control Plane",
Type: "http",
Port: 6443,
BindToVip: true,
Backends: []BackEnd{
{
Address: "192.168.0.100",
Port: 6443,
},
{
Address: "192.168.0.101",
Port: 6443,
},
{
Address: "192.168.0.102",
Port: 6443,
},
},
},
},
func isValidInterface(iface string) error {
// auto interface discovery for services is enabled
if iface == Auto {
return nil
}
b, _ := yaml.Marshal(c)
fmt.Printf(string(b))
}
//WriteConfig will write the current configuration to a specified [path]
func (c *Config) WriteConfig(path string) error {
f, err := os.Create(path)
l, err := netlink.LinkByName(iface)
if err != nil {
return err
return fmt.Errorf("get %s failed, error: %w", iface, err)
}
defer f.Close()
attrs := l.Attrs()
b, err := yaml.Marshal(c)
if err != nil {
return err
// Some interfaces (included but not limited to lo and point-to-point
// interfaces) do not provide a operational status but are safe to use.
// From kernek.org: "Interface is in unknown state, neither driver nor
// userspace has set operational state. Interface must be considered for user
// data as setting operational state has not been implemented in every driver."
if attrs.OperState == netlink.OperUnknown {
log.Warn(
"the status of the interface is unknown. Ensure your interface is ready to accept traffic, if so you can safely ignore this message", "interface",
iface,
)
} else if attrs.OperState != netlink.OperUp {
return fmt.Errorf("%s is not up", iface)
}
bytesWritten, err := f.Write(b)
if err != nil {
return err
}
log.Debugf("wrote %d bytes\n", bytesWritten)
return nil
}

View File

@@ -1,27 +1,98 @@
package kubevip
import "net/url"
import (
"github.com/kube-vip/kube-vip/pkg/bgp"
)
// Config defines all of the settings for the Virtual IP / Load-balancer
// Config defines all of the settings for the Kube-Vip Pod
type Config struct {
// Logging, settings
Logging int32 `yaml:"logging"`
// EnableLeaderElection will use the Kubernetes leader election algorithim
EnableLeaderElection bool `yaml:"enableLeaderElection"`
// EnableARP, will use ARP to advertise the VIP address
EnableARP bool `yaml:"enableARP"`
// LocalPeer is the configuration of this host
LocalPeer RaftPeer `yaml:"localPeer"`
// EnableBGP, will use BGP to advertise the VIP address
EnableBGP bool `yaml:"enableBGP"`
// Peers are all of the peers within the RAFT cluster
RemotePeers []RaftPeer `yaml:"remotePeers"`
// EnableWireguard, will use wireguard to advertise the VIP address
EnableWireguard bool `yaml:"enableWireguard"`
// EnableRoutingTable, will use the routing table to advertise the VIP address
EnableRoutingTable bool `yaml:"enableRoutingTable"`
// EnableControlPlane, will enable the control plane functionality (used for hybrid behaviour)
EnableControlPlane bool `yaml:"enableControlPlane"`
// DetectControlPlane, will attempt to find the control plane from loopback (127.0.0.1)
DetectControlPlane bool `yaml:"detectControlPlane"`
// KubernetesAddris the address of the Kubernetes API server on this machine
KubernetesAddr string `yaml:"kubernetesAddr"`
// EnableServices, will enable the services functionality (used for hybrid behaviour)
EnableServices bool `yaml:"enableServices"`
// EnableServicesElection, will enable leaderElection per service
EnableServicesElection bool `yaml:"enableServicesElection"`
// EnableNodeLabeling, will enable node labeling as it becomes leader
EnableNodeLabeling bool `yaml:"enableNodeLabeling"`
// LoadBalancerClassOnly, will enable load balancing only for services with LoadBalancerClass set to "kube-vip.io/kube-vip-class"
LoadBalancerClassOnly bool `yaml:"lbClassOnly"`
// LoadBalancerClassName, will limit the load balancing services to services with LoadBalancerClass set to this value
LoadBalancerClassName string `yaml:"lbClassName"`
// LoadBalancerClassLegacyHandling, will enable legacy loadbalancer class handling which does not force service loadbalancer class and kube-vip's loadbalancer class to be the same.
LoadBalancerClassLegacyHandling bool `yaml:"lbClassNameLegacyHandling"`
// EnableServiceSecurity, will enable the use of iptables to secure services
EnableServiceSecurity bool `yaml:"EnableServiceSecurity"`
// ArpBroadcastRate, defines how often kube-vip will update the network about updates to the network
ArpBroadcastRate int64 `yaml:"arpBroadcastRate"`
// Annotations will define if we're going to wait and lookup configuration from Kubernetes node annotations
Annotations string
// LeaderElectionType defines the backend to run the leader election: kubernetes or etcd. Defaults to kubernetes.
// Etcd doesn't support load balancer mode (EnableLoadBalancer=true) or any other feature that depends on the kube-api server.
LeaderElectionType string `yaml:"leaderElectionType"`
// KubernetesLeaderElection defines the settings around Kubernetes KubernetesLeaderElection
KubernetesLeaderElection
// Etcd defines all the settings for the etcd client.
Etcd Etcd
// AddPeersAsBackends, this will automatically add RAFT peers as backends to a loadbalancer
AddPeersAsBackends bool `yaml:"addPeersAsBackends"`
// VIP is the Virtual IP address exposed for the cluster
// VIP is the Virtual IP address exposed for the cluster (TODO: deprecate)
VIP string `yaml:"vip"`
// GratuitousARP will broadcast an ARP update when the VIP changes host
GratuitousARP bool `yaml:"gratuitousARP"`
// VipSubnet is the Subnet that is applied to the VIP
VIPSubnet string `yaml:"vipSubnet"`
// Address is the IP or DNS Name to use as a VirtualIP
Address string `yaml:"address"`
// Listen port for the VirtualIP
Port uint16 `yaml:"port"`
// Namespace will define which namespace the control plane pods will run in
Namespace string `yaml:"namespace"`
// Namespace will define which namespace the control plane pods will run in
ServiceNamespace string `yaml:"serviceNamespace"`
// use DDNS to allocate IP when Address is set to a DNS Name
DDNS bool `yaml:"ddns"`
// NodeName - used for matching node name from pod spec
NodeName string `yaml:"leaseNodeName"`
// SingleNode will start the cluster as a single Node (Raft disabled)
SingleNode bool `yaml:"singleNode"`
@@ -32,32 +103,118 @@ type Config struct {
// Interface is the network interface to bind to (default: First Adapter)
Interface string `yaml:"interface,omitempty"`
// ServicesInterface is the network interface to bind to for services (optional)
ServicesInterface string `yaml:"servicesInterface,omitempty"`
// EnableLoadBalancer, provides the flexibility to make the load-balancer optional
EnableLoadBalancer bool `yaml:"enableLoadBalancer"`
// EnablePacket, will use the packet API to update the EIP <-> VIP
EnablePacket bool `yaml:"enablePacket"`
// Listen port for the IPVS Service
LoadBalancerPort uint16 `yaml:"lbPort"`
// PacketAPIKey, is the API token used to authenticate to the API
PacketAPIKey string
// Forwarding method for the IPVS Service
LoadBalancerForwardingMethod string `yaml:"lbForwardingMethod"`
// PacketProject, is the name of a particular defined project
PacketProject string
// Routing Table ID for when using routing table mode
RoutingTableID int `yaml:"routingTableID"`
// Routing Table Type, what sort of route should be added to the routing table
RoutingTableType int `yaml:"routingTableType"`
// Routing Protocol, value that will be used as protocol when creating rutes
RoutingProtocol int `yaml:"routingProtocol"`
// Clean routing table of redundant routes on start
CleanRoutingTable bool `yaml:"cleanRoutingTable"`
// BGP Configuration
BGPConfig bgp.Config
BGPPeerConfig bgp.Peer
BGPPeers []string
// LoadBalancers are the various services we can load balance over
LoadBalancers []LoadBalancer `yaml:"loadBalancers,omitempty"`
// The hostport used to expose Prometheus metrics over an HTTP server
PrometheusHTTPServer string `yaml:"prometheusHTTPServer,omitempty"`
// Egress configuration
// EgressPodCidr, this contains the pod cidr range to ignore Egress
EgressPodCidr string
// EgressServiceCidr, this contains the service cidr range to ignore
EgressServiceCidr string
// EgressWithNftables, this will use the iptables-nftables OVER iptables
EgressWithNftables bool
// ServicesLeaseName, this will set the lease name for services leader in arp mode
ServicesLeaseName string `yaml:"servicesLeaseName"`
// K8sConfigFile, this is the path to the config file used to speak with the API server
K8sConfigFile string `yaml:"k8sConfigFile"`
// DNSMode, this will set the mode DSN lookup will be performed (first, ipv4, ipv6, dual)
DNSMode string `yaml:"dnsDualStackMode"`
// DisableServiceUpdates, if true, kube-vip will only advertise service, but it will not update service's Status.LoadBalancer.Ingress slice
DisableServiceUpdates bool `yaml:"disableServiceUpdates"`
// EnableEndpoints, if enabled, Endpoints will be used instead of EndpointSlices
EnableEndpoints bool `yaml:"enableEndpoints"`
// MirrorDestInterface is the network interface where all traffics that go through service interface
// will be mirrored to. If ServicesInterface is not set, fall back to Interface.
// + optional
MirrorDestInterface string `yaml:"mirrorDestInterface"`
// IptablesBackend iptables backend, can be specified as `nft` or `legacy`. If not set, it defaults to automatic detection.
IptablesBackend string `yaml:"iptablesBackend"`
// BackendHealthCheckInterval Interval in seconds for checking backend health.
BackendHealthCheckInterval int `yaml:"backendHealthCheckInterval"`
// LoInterfaceGlobalScope, if true will set global scope when using the lo interface, otherwise a host scope will be used
LoInterfaceGlobalScope bool `yaml:"loInterfaceGlobalScope"`
// HealthCheckPort, if non-zero then will enable the healthcheck to return ok on this port
HealthCheckPort int `yaml:"healthCheckPort"`
// EnableUPNP, enables UPNP functions
EnableUPNP bool `yaml:"enableUPNP"`
// EgressClean, enables egress cleaning on Kube-vip's start
EgressClean bool `yaml:"egressClean"`
}
// RaftPeer details the configuration of all cluster peers
type RaftPeer struct {
// ID is the unique identifier a peer instance
ID string `yaml:"id"`
// KubernetesLeaderElection defines all of the settings for Kubernetes KubernetesLeaderElection
type KubernetesLeaderElection struct {
// EnableLeaderElection will use the Kubernetes leader election algorithm
EnableLeaderElection bool `yaml:"enableLeaderElection"`
// IP Address of a peer instance
Address string `yaml:"address"`
// LeaseName - name of the lease for leader election
LeaseName string `yaml:"leaseName"`
// Listening port of this peer instance
Port int `yaml:"port"`
// Lease Duration - length of time a lease can be held for
LeaseDuration int
// RenewDeadline - length of time a host can attempt to renew its lease
RenewDeadline int
// RetryPeriod - length of time (in seconds) the LeaderElector clients should wait between tries of actions
RetryPeriod int
// LeaseAnnotations - annotations which will be given to the lease object
LeaseAnnotations map[string]string
}
// Etcd defines all the settings for the etcd client.
type Etcd struct {
CAFile string
ClientCertFile string
ClientKeyFile string
Endpoints []string
}
// LoadBalancer contains the configuration of a load balancing instance
@@ -65,33 +222,20 @@ type LoadBalancer struct {
// Name of a LoadBalancer
Name string `yaml:"name"`
// Type of LoadBalancer, either TCP of HTTP(s)
Type string `yaml:"type"`
// Listening frontend port of this LoadBalancer instance
Port int `yaml:"port"`
//Ports exposed by a LoadBalancer
Ports []Port
// BindToVip will bind the load balancer port to the VIP itself
BindToVip bool `yaml:"bindToVip"`
//BackendPort, is a port that all backends are listening on (To be used to simplify building a list of backends)
BackendPort int `yaml:"backendPort"`
//Backends, is an array of backend servers
Backends []BackEnd `yaml:"backends"`
// Forwarding method of LoadBalancer, either Local, Tunnel, DirectRoute or Bypass
ForwardingMethod string `yaml:"forwardingMethod"`
}
// BackEnd is a server we will load balance over
type BackEnd struct {
// Backend Port to Load Balance to
type Port struct {
// Type of LoadBalancer, either TCP or UDP
Type string `yaml:"type"`
// Listening frontend port of this LoadBalancer instance
Port int `yaml:"port"`
// Address of a server/service
Address string `yaml:"address"`
// URL is a raw URL to a backend service
RawURL string `yaml:"url,omitempty"`
// ParsedURL - A validated URL to a backend
ParsedURL *url.URL `yaml:"parsedURL,omitempty"`
}

391
pkg/loadbalancer/ipvs.go Normal file
View File

@@ -0,0 +1,391 @@
package loadbalancer
import (
"context"
"errors"
"fmt"
"net"
"net/netip"
"os"
"strings"
"sync"
log "log/slog"
"github.com/cloudflare/ipvs"
"github.com/cloudflare/ipvs/netmask"
"github.com/kube-vip/kube-vip/pkg/backend"
"github.com/kube-vip/kube-vip/pkg/sysctl"
"github.com/kube-vip/kube-vip/pkg/vip"
"github.com/vishvananda/netlink"
)
/*
IPVS Architecture - for those that are interested
There are going to be a large number of end users that are using a VIP that exists within the same subnet
as the back end servers. This unfortunately will result in "packet" confusion with the destingation and
source becoming messed up by the IPVS NAT.
The solution is to perform two things !
First:
Set up kube-vip TCP port forwarder from the VIP:PORT to the IPVS:PORT
Second:
Start up a node watcher and a IPVS load balancer, the node balancer is responsible for adding/removing
the nodes from the IPVS load-balancer.
*/
const (
ROUNDROBIN = "rr"
)
type IPVSLoadBalancer struct {
client ipvs.Client
loadBalancerService ipvs.Service
Port uint16
forwardingMethod ipvs.ForwardType
backendMap backend.Map
interval int
lock sync.Mutex
stop chan struct{}
networkInterface string
leaderCancel context.CancelFunc
signal chan os.Signal
address string
family ipvs.AddressFamily
}
func NewIPVSLB(address string, port uint16, forwardingMethod string, backendHealthCheckInterval int, networkInterface string, leaderCancel context.CancelFunc, signal chan os.Signal) (*IPVSLoadBalancer, error) {
log.Info("Starting IPVS LoadBalancer", "address", address)
// Create IPVS client
c, err := ipvs.New()
if err != nil {
log.Error("ensure IPVS kernel modules are loaded")
log.Error("Error starting IPVS", "err", err)
panic("")
}
i, err := c.Info()
if err != nil {
log.Error("ensure IPVS kernel modules are loaded")
log.Error("Error retrieving IPVS info", "err", err)
if errors.Is(err, os.ErrPermission) {
log.Error("no permission to get IPVS info - please ensure that kube-vip is running with proper capabilities/privileged mode")
}
panic("")
}
log.Info("IPVS Loadbalancer enabled", "version", fmt.Sprintf("%d.%d.%d", i.Version[0], i.Version[1], i.Version[2]))
ip, family := ipAndFamily(address)
if strings.ToLower(forwardingMethod) == "masquerade" {
enableProcSys("/proc/sys/net/ipv4/vs/conntrack", "net.ipv4.vs.conntrack")
if family == ipvs.INET6 {
enableProcSys("/proc/sys/net/ipv6/conf/all/forwarding", "net.ipv6.conf.all.forwarding")
} else {
enableProcSys("/proc/sys/net/ipv4/ip_forward", "net.ipv4.ip_forward")
}
}
netMask := netmask.MaskFrom(31, 32) // For ipv4
if family == ipvs.INET6 {
netMask = netmask.MaskFrom(128, 128) // For ipv6
}
// Generate out API Server LoadBalancer instance
svc := ipvs.Service{
Netmask: netMask,
Family: family,
Protocol: ipvs.TCP,
Port: port,
Address: ip,
Scheduler: ROUNDROBIN,
}
var m ipvs.ForwardType
switch strings.ToLower(forwardingMethod) {
case "masquerade":
m = ipvs.Masquerade
case "local":
m = ipvs.Local
case "tunnel":
m = ipvs.Tunnel
case "directroute":
m = ipvs.DirectRoute
case "bypass":
m = ipvs.Bypass
default:
m = ipvs.Local
log.Warn("unknown forwarding method. Defaulting to Local")
}
if backendHealthCheckInterval <= 0 {
backendHealthCheckInterval = 5
}
lb := &IPVSLoadBalancer{
Port: port,
client: c,
loadBalancerService: svc,
forwardingMethod: m,
interval: backendHealthCheckInterval,
backendMap: make(backend.Map),
stop: make(chan struct{}),
networkInterface: networkInterface,
leaderCancel: leaderCancel,
signal: signal,
address: address,
family: family,
}
go lb.healthCheck()
// Return our created load-balancer
return lb, nil
}
func enableProcSys(path, name string) {
isSet, err := sysctl.EnableProcSys(path)
if err != nil {
log.Error(fmt.Sprintf("ensuring %s enabled", name), "err", err)
panic("")
}
if isSet {
log.Info(fmt.Sprintf("sysctl set %s to 1", name))
}
}
func (lb *IPVSLoadBalancer) RemoveIPVSLB() error {
log.Info("Stopping IPVS LoadBalancer", "address", lb.address)
close(lb.stop)
err := lb.client.RemoveService(lb.loadBalancerService)
if err != nil {
return fmt.Errorf("error removing existing IPVS service: %v", err)
}
return nil
}
func (lb *IPVSLoadBalancer) AddBackend(address string, port uint16) error {
isLocal := false
var err error
// Discard backend if it is of different IP family than LB address.
if _, family := ipAndFamily(address); family != lb.family {
return nil
}
if lb.forwardingMethod == ipvs.Local {
log.Info("checking if backend is local", "addr", address)
isLocal, err = lb.isLocal(address)
if err != nil {
log.Error("checking if backend is local", "err", err)
}
}
backend := backend.Entry{Addr: address, Port: port, IsLocal: isLocal}
lb.lock.Lock()
defer lb.lock.Unlock()
if _, ok := lb.backendMap[backend]; !ok {
isHealth := backend.Check()
if isHealth {
err := lb.addBackend(address, port)
if err != nil {
return err
}
}
lb.backendMap[backend] = isHealth
}
return nil
}
func (lb *IPVSLoadBalancer) addBackend(address string, port uint16) error {
backend := backend.Entry{Addr: address, Port: port}
// Check if this is the first backend
backends, err := lb.client.Destinations(lb.loadBalancerService)
if err != nil && strings.Contains(err.Error(), "file does not exist") {
log.Error("querying backends", "err", err)
}
// If this is our first backend, then we can create the load-balancer service and add a backend
if len(backends) == 0 {
err = lb.client.CreateService(lb.loadBalancerService)
// If we've an error it could be that the IPVS lb instance has been left from a previous leadership
if err != nil && strings.Contains(err.Error(), "file exists") {
log.Warn("load balancer for API server already exists, attempting to remove and re-create")
err = lb.client.RemoveService(lb.loadBalancerService)
if err != nil {
return fmt.Errorf("error re-creating IPVS service: %v", err)
}
err = lb.client.CreateService(lb.loadBalancerService)
if err != nil {
return fmt.Errorf("error re-creating IPVS service: %v", err)
}
} else if err != nil {
// Fatal error at this point as IPVS is probably not working
log.Error("Unable to create an IPVS service, ensure IPVS kernel modules are loaded")
log.Error("IPVS service", "err", err)
panic("")
}
log.Info("load-Balancer services created", "address", lb.addrString(), "port", lb.Port)
}
ip, family := ipAndFamily(backend.Addr)
// Ignore backends that use a different address family.
// Looks like different families could be supported in tunnel mode...
if family != lb.loadBalancerService.Family {
return nil
}
dst := ipvs.Destination{
Address: ip,
Port: backend.Port,
Family: family,
Weight: 1,
FwdMethod: lb.forwardingMethod,
}
err = lb.client.CreateDestination(lb.loadBalancerService, dst)
// Swallow error of existing back end, the node watcher may attempt to apply
// the same back end multiple times
if err != nil {
if !strings.Contains(err.Error(), "file exists") {
return fmt.Errorf("error creating backend: %v", err)
}
// file exists is fine, we will just return at this point
return nil
}
log.Info("backend added", "src addr", lb.addrString(), "src port", lb.Port, "dst addr", backend.Addr, "dst port", backend.Port)
return nil
}
func (lb *IPVSLoadBalancer) RemoveBackend(address string, port uint16) error {
backend := backend.Entry{Addr: address, Port: port}
lb.lock.Lock()
defer lb.lock.Unlock()
if _, ok := lb.backendMap[backend]; ok {
err := lb.removeBackend(address, port)
if err != nil {
return err
}
delete(lb.backendMap, backend)
}
return nil
}
func (lb *IPVSLoadBalancer) removeBackend(address string, port uint16) error {
ip, family := ipAndFamily(address)
if family != lb.loadBalancerService.Family {
return nil
}
dst := ipvs.Destination{
Address: ip,
Port: port,
Family: family,
Weight: 1,
}
err := lb.client.RemoveDestination(lb.loadBalancerService, dst)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("error removing backend: %v", err)
}
return nil
}
func (lb *IPVSLoadBalancer) addrString() string {
return lb.loadBalancerService.Address.String()
}
func ipAndFamily(address string) (netip.Addr, ipvs.AddressFamily) {
ipAddr := net.ParseIP(address)
if ipAddr.To4() == nil {
return netip.AddrFrom16([16]byte(ipAddr.To16())), ipvs.INET6
}
return netip.AddrFrom4([4]byte(ipAddr.To4())), ipvs.INET
}
func (lb *IPVSLoadBalancer) healthCheck() {
backend.Watch(func() {
lb.lock.Lock()
defer lb.lock.Unlock()
for backend, oldStatus := range lb.backendMap {
newStatus := backend.Check()
if newStatus {
// old status -> health
if !oldStatus {
err := lb.addBackend(backend.Addr, backend.Port)
if err != nil {
log.Error("add backend", "err", err)
}
lb.backendMap[backend] = newStatus
}
} else {
// old status -> not health
if oldStatus {
log.Info("healthCheck failed - removing backend", "address", backend.Addr, "port", backend.Port)
err := lb.removeBackend(backend.Addr, backend.Port)
if err != nil {
log.Error("failed to remove backend", "address", backend.Addr, "port", backend.Port, "err", err)
}
lb.backendMap[backend] = newStatus
}
if lb.forwardingMethod == ipvs.Local && !lb.localBackendExists() {
if lb.signal != nil {
close(lb.signal)
}
if lb.leaderCancel != nil {
lb.leaderCancel()
}
}
}
}
}, lb.interval, lb.stop)
}
func (lb *IPVSLoadBalancer) isLocal(address string) (bool, error) {
link, err := netlink.LinkByName(lb.networkInterface)
if err != nil {
return false, fmt.Errorf("getting link '%s': %w", lb.networkInterface, err)
}
family := netlink.FAMILY_V6
if vip.IsIPv4(address) {
family = netlink.FAMILY_V4
}
target := net.ParseIP(address)
if target == nil {
return false, fmt.Errorf("address '%s' is not a valid IP address", address)
}
addrs, err := netlink.AddrList(link, family)
if err != nil {
return false, fmt.Errorf("listing addresses for link '%s': %w", lb.networkInterface, err)
}
for _, addr := range addrs {
if addr.IP.Equal(target) {
return true, nil
}
}
return false, nil
}
func (lb *IPVSLoadBalancer) localBackendExists() bool {
for backend, isHealthy := range lb.backendMap {
if backend.IsLocal && isHealthy {
return true
}
}
return false
}

View File

@@ -0,0 +1,49 @@
package loadbalancer
import (
"net/netip"
"reflect"
"testing"
"github.com/cloudflare/ipvs"
)
func Test_ipAndFamily(t *testing.T) {
type args struct {
address string
}
tests := []struct {
name string
args args
want netip.Addr
want1 ipvs.AddressFamily
}{
{
name: "IPv4",
args: args{
address: "192.168.0.20",
},
want: netip.AddrFrom4([4]byte{192, 168, 0, 20}),
want1: ipvs.INET,
},
{
name: "IPv6",
args: args{
address: "ff02::3",
},
want: netip.AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x03}),
want1: ipvs.INET6,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := ipAndFamily(tt.args.address)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ipAndFamily() got = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got1, tt.want1) {
t.Errorf("ipAndFamily() got1 = %v, want %v", got1, tt.want1)
}
})
}
}

View File

@@ -1,129 +0,0 @@
package loadbalancer
import (
"io"
"net"
"sync"
"time"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
)
// 1. Load balancer port is exposed
// 2. We listen
// 3. On connection we connect to an endpoint
// [loop]
// 4. We read from the load balancer port
// 5. We write traffic to the endpoint
// 6. We read response from endpoint
// 7. We write response to load balancer
// [goto loop]
func persistentConnection(frontendConnection net.Conn, lb *kubevip.LoadBalancer) {
var endpoint net.Conn
defer frontendConnection.Close()
// Makes sure we close the connections to the endpoint when we've completed
// Set a timeout for connecting to an endpoint
dialer := net.Dialer{Timeout: time.Millisecond * 500}
for {
// Connect to Endpoint
ep, err := lb.ReturnEndpointAddr()
if err != nil {
return
}
// We now dial to an endpoint with a timeout of half a second
// TODO - make this adjustable
endpoint, err = dialer.Dial("tcp", ep)
if err != nil {
log.Debugf("%v", err)
log.Warnf("[%s]---X [FAILED] X-->[%s]", frontendConnection.RemoteAddr(), ep)
} else {
log.Debugf("[%s]---->[ACCEPT]---->[%s]", frontendConnection.RemoteAddr(), ep)
defer endpoint.Close()
break
}
}
wg := &sync.WaitGroup{}
wg.Add(1)
// Begin copying incoming (frontend -> to an endpoint)
go func() {
bytes, err := io.Copy(endpoint, frontendConnection)
log.Debugf("[%d] bytes of data sent to endpoint", bytes)
if err != nil {
log.Warnf("Error sending data to endpoint [%s] [%v]", endpoint.RemoteAddr(), err)
}
wg.Done()
}()
// go func() {
// Begin copying recieving (endpoint -> back to frontend)
bytes, err := io.Copy(frontendConnection, endpoint)
log.Debugf("[%d] bytes of data sent to client", bytes)
if err != nil {
log.Warnf("Error sending data to frontend [%s] [%s]", frontendConnection.RemoteAddr(), err)
}
// wg.Done()
// endpoint.Close()
// }()
wg.Wait()
}
func persistentUDPConnection(frontendConnection net.Conn, lb *kubevip.LoadBalancer) {
var endpoint net.Conn
defer frontendConnection.Close()
// Makes sure we close the connections to the endpoint when we've completed
// Set a timeout for connecting to an endpoint
dialer := net.Dialer{Timeout: time.Millisecond * 500}
for {
// Connect to Endpoint
ep, err := lb.ReturnEndpointAddr()
if err != nil {
return
}
// We now dial to an endpoint with a timeout of half a second
// TODO - make this adjustable
endpoint, err = dialer.Dial("udp", ep)
if err != nil {
log.Debugf("%v", err)
log.Warnf("[%s]---X [FAILED] X-->[%s]", frontendConnection.RemoteAddr(), ep)
} else {
log.Debugf("[%s]---->[ACCEPT]---->[%s]", frontendConnection.RemoteAddr(), ep)
defer endpoint.Close()
break
}
}
wg := &sync.WaitGroup{}
wg.Add(1)
// Begin copying incoming (frontend -> to an endpoint)
go func() {
bytes, err := io.Copy(endpoint, frontendConnection)
log.Debugf("[%d] bytes of data sent to endpoint", bytes)
if err != nil {
log.Warnf("Error sending data to endpoint [%s] [%v]", endpoint.RemoteAddr(), err)
}
wg.Done()
}()
// go func() {
// Begin copying recieving (endpoint -> back to frontend)
bytes, err := io.Copy(frontendConnection, endpoint)
log.Debugf("[%d] bytes of data sent to client", bytes)
if err != nil {
log.Warnf("Error sending data to frontend [%s] [%s]", frontendConnection.RemoteAddr(), err)
}
// wg.Done()
// endpoint.Close()
// }()
wg.Wait()
}

View File

@@ -1,126 +0,0 @@
package loadbalancer
import (
"context"
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"time"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
)
func (lb *LBInstance) startHTTP(bindAddress string) error {
log.Infof("Starting TCP Load Balancer for service [%s]", lb.instance.Name)
// Validate the back end URLS
err := kubevip.ValidateBackEndURLS(&lb.instance.Backends)
if err != nil {
return err
}
frontEnd := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port)
handler := func(w http.ResponseWriter, req *http.Request) {
// parse the url
url, _ := url.Parse(lb.instance.ReturnEndpointURL().String())
// create the reverse proxy
proxy := httputil.NewSingleHostReverseProxy(url)
// Update the headers to allow for SSL redirection
req.URL.Host = url.Host
req.URL.Scheme = url.Scheme
req.Header.Set("X-Forwarded-Host", req.Host)
req.Host = url.Host
//Print out the response (if debug logging)
if log.GetLevel() == log.DebugLevel {
fmt.Printf("Host:\t%s\n", req.Host)
fmt.Printf("Request:\t%s\n", req.Method)
fmt.Printf("URI:\t%s\n", req.RequestURI)
for key, value := range req.Header {
fmt.Println("Header:", key, "Value:", value)
}
}
// Note that ServeHttp is non blocking and uses a go routine under the hood
proxy.ServeHTTP(w, req)
}
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
log.Infof("Starting server listening [%s]", frontEnd)
server := &http.Server{Addr: frontEnd, Handler: mux}
go func() error {
if err := server.ListenAndServe(); err != nil {
return err
}
return nil
}()
// If the stop channel is closed then the server will be gracefully shut down
<-lb.stop
log.Infof("Stopping the load balancer [%s] bound to [%s] with 5sec timeout", lb.instance.Name, frontEnd)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
return err
}
close(lb.stopped)
return nil
}
//StartHTTP - begins the HTTP load balancer
func StartHTTP(lb *kubevip.LoadBalancer, address string) error {
log.Infof("Starting TCP Load Balancer for service [%s]", lb.Name)
// Validate the back end URLS
err := kubevip.ValidateBackEndURLS(&lb.Backends)
if err != nil {
return err
}
frontEnd := fmt.Sprintf("%s:%d", address, lb.Port)
handler := func(w http.ResponseWriter, req *http.Request) {
// parse the url
url, _ := url.Parse(lb.ReturnEndpointURL().String())
// create the reverse proxy
proxy := httputil.NewSingleHostReverseProxy(url)
// Update the headers to allow for SSL redirection
req.URL.Host = url.Host
req.URL.Scheme = url.Scheme
req.Header.Set("X-Forwarded-Host", req.Host)
req.Host = url.Host
//Print out the response (if debug logging)
if log.GetLevel() == log.DebugLevel {
fmt.Printf("Host:\t%s\n", req.Host)
fmt.Printf("Request:\t%s\n", req.Method)
fmt.Printf("URI:\t%s\n", req.RequestURI)
for key, value := range req.Header {
fmt.Println("Header:", key, "Value:", value)
}
}
// Note that ServeHttp is non blocking and uses a go routine under the hood
proxy.ServeHTTP(w, req)
}
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
log.Infof("Starting server listening [%s]", frontEnd)
http.ListenAndServe(frontEnd, mux)
// Should never get here
return nil
}

View File

@@ -1,178 +0,0 @@
package loadbalancer
import (
"bytes"
"fmt"
"io"
"net"
"time"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
)
// StartTCP a TCP load balancer server instane
func (lb *LBInstance) startTCP(bindAddress string) error {
fullAddress := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port)
log.Infof("Starting TCP Load Balancer for service [%s]", fullAddress)
laddr, err := net.ResolveTCPAddr("tcp", fullAddress)
if nil != err {
log.Errorln(err)
}
l, err := net.ListenTCP("tcp", laddr)
if nil != err {
return fmt.Errorf("Unable to bind [%s]", err.Error())
}
go func() {
for {
select {
case <-lb.stop:
log.Debugln("Closing listener")
// We've closed the stop channel
err = l.Close()
if err != nil {
return
}
// Close the stopped channel as the listener has been stopped
close(lb.stopped)
default:
err = l.SetDeadline(time.Now().Add(200 * time.Millisecond))
if err != nil {
log.Errorf("Error setting TCP deadline", err)
}
fd, err := l.Accept()
if err != nil {
// Check it it's an accept timeout
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
continue
} else if err != io.EOF {
log.Errorf("TCP Accept error [%s]", err)
}
}
go persistentConnection(fd, lb.instance)
}
}
}()
log.Infof("Load Balancer [%s] started", lb.instance.Name)
return nil
}
// startTCPDNU - Start TCP service Do not use
// This stops the service by closing the listener and then ignorning the error from Accept()
func (lb *LBInstance) startTCPDNU(bindAddress string) error {
fullAddress := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port)
log.Infof("Starting TCP Load Balancer for service [%s]", fullAddress)
//l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port))
laddr, err := net.ResolveTCPAddr("tcp", fullAddress)
if nil != err {
log.Errorln(err)
}
l, err := net.ListenTCP("tcp", laddr)
if nil != err {
return fmt.Errorf("Unable to bind [%s]", err.Error())
}
go func() {
<-lb.stop
log.Debugln("Closing listener")
// We've closed the stop channel
err = l.Close()
if err != nil {
return
}
// Close the stopped channel as the listener has been stopped
close(lb.stopped)
}()
go func() {
for {
fd, err := l.Accept()
if err != nil {
// Check it it's an accept timeout
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
continue
} else if err != io.EOF {
log.Errorf("TCP Accept error [%s]", err)
return
}
}
go persistentConnection(fd, lb.instance)
//go processRequests(lb.instance, fd)
}
// }
}()
log.Infof("Load Balancer [%s] started", lb.instance.Name)
return nil
}
// user -> [LB]
// [LB] (select end pot) -> [endpoint]
//
//
//
//
//
//
func processRequests(lb *kubevip.LoadBalancer, frontendConnection net.Conn) {
for {
// READ FROM client
buf := make([]byte, 1024*1024)
datalen, err := frontendConnection.Read(buf)
if err != nil {
log.Fatalf("%v", err)
}
log.Debugf("Sent [%d] bytes to the LB", datalen)
data := buf[0:datalen]
// Connect to Endpoint
ep, err := lb.ReturnEndpointAddr()
if err != nil {
log.Errorf("No Backends available")
}
log.Debugf("Attempting endpoint [%s]", ep)
endpoint, err := net.Dial("tcp", ep)
if err != nil {
fmt.Println("dial error:", err)
// return nil, err
}
log.Debugf("succesfully connected to [%s]", ep)
// Set a timeout
endpoint.SetReadDeadline(time.Now().Add(time.Second * 1))
b, err := endpointRequest(endpoint, ep, string(data))
_, err = frontendConnection.Write(b)
if err != nil {
log.Fatal("Write: ", err)
}
}
}
// endpointRequest will take an endpoint address and send the data and wait for the response
func endpointRequest(endpoint net.Conn, endpointAddr, request string) ([]byte, error) {
// defer conn.Close()
datalen, err := fmt.Fprintf(endpoint, request)
if err != nil {
fmt.Println("dial error:", err)
return nil, err
}
log.Debugf("Sent [%d] bytes to the endpoint", datalen)
var b bytes.Buffer
io.Copy(&b, endpoint)
log.Debugf("Recieved [%d] from the endpoint", b.Len())
return b.Bytes(), nil
}

View File

@@ -1,103 +0,0 @@
package loadbalancer
import (
"fmt"
"net"
log "github.com/sirupsen/logrus"
)
// StartTCP a TCP load balancer server instane
func (lb *LBInstance) startUDP(bindAddress string) error {
fullAddress := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port)
log.Infof("Starting UDP Load Balancer for service [%s]", fullAddress)
laddr, err := net.ResolveUDPAddr("udp", fullAddress)
if nil != err {
log.Errorln(err)
}
l, err := net.ListenUDP("udp", laddr)
if nil != err {
return fmt.Errorf("Unable to bind [%s]", err.Error())
}
//stopListener := make(chan bool)
go func() {
for {
select {
case <-lb.stop:
log.Debugln("Closing listener")
// We've closed the stop channel
err = l.Close()
if err != nil {
return
}
// Close the stopped channel as the listener has been stopped
close(lb.stopped)
default:
// err = l.SetDeadline(time.Now().Add(200 * time.Millisecond))
// if err != nil {
// log.Errorf("Error setting TCP deadline", err)
// }
// fd, err := l.Accept()
// if err != nil {
// // Check it it's an accept timeout
// if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
// continue
// } else if err != io.EOF {
// log.Errorf("TCP Accept error [%s]", err)
// }
// }
go persistentUDPConnection(l, lb.instance)
}
}
}()
log.Infof("Load Balancer [%s] started", lb.instance.Name)
// go func() {
// <-lb.stop
// log.Debugln("Closing listener")
// // We've closed the stop channel
// err = l.Close()
// if err != nil {
// return
// }
// // Close the stopped channel as the listener has been stopped
// close(stopListener)
// }()
// // Create a listener per CPU
// // TODO - make this customisable?
// //for i := 0; i < runtime.NumCPU(); i++ {
// go persistentUDPConnection(l, lb.instance)
// //}
//<-stopListener // hang until an error
log.Infof("Load Balancer [%s] started", lb.instance.Name)
return nil
}
// func listen(connection *net.UDPConn, quit chan bool) {
// buffer := make([]byte, 1024)
// n, remoteAddr, err := 0, new(net.UDPAddr), error(nil)
// for err == nil {
// //TODO -
// n, remoteAddr, err = connection.ReadFromUDP(buffer)
// // you might copy out the contents of the packet here, to
// // `var r myapp.Request`, say, and `go handleRequest(r)` (or
// // send it down a channel) to free up the listening
// // goroutine. you do *need* to copy then, though,
// // because you've only made one buffer per listen().
// fmt.Println("from", remoteAddr, "-", buffer[:n])
// }
// fmt.Println("listener failed - ", err)
// }

View File

@@ -1,78 +0,0 @@
package loadbalancer
import (
"fmt"
"strings"
"github.com/plunder-app/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
)
//LBInstance - manages the state of load balancer instances
type LBInstance struct {
stop chan bool // Asks LB to stop
stopped chan bool // LB is stopped
instance *kubevip.LoadBalancer // pointer to a LB instance
// mux sync.Mutex
}
//LBManager - will manage a number of load blancer instances
type LBManager struct {
loadBalancer []LBInstance
}
//Add - handles the building of the load balancers
func (lm *LBManager) Add(bindAddress string, lb *kubevip.LoadBalancer) error {
newLB := LBInstance{
stop: make(chan bool, 1),
stopped: make(chan bool, 1),
instance: lb,
}
switch strings.ToLower(lb.Type) {
case "tcp":
err := newLB.startTCP(bindAddress)
if err != nil {
return err
}
case "udp":
err := newLB.startUDP(bindAddress)
if err != nil {
return err
}
case "http":
err := newLB.startHTTP(bindAddress)
if err != nil {
return err
}
default:
return fmt.Errorf("Unknown Load Balancer type [%s]", lb.Type)
}
lm.loadBalancer = append(lm.loadBalancer, newLB)
return nil
}
//StopAll - handles the building of the load balancers
func (lm *LBManager) StopAll() error {
log.Debugf("Stopping [%d] loadbalancer instances", len(lm.loadBalancer))
for x := range lm.loadBalancer {
err := lm.loadBalancer[x].Stop()
if err != nil {
return err
}
}
// Reset the loadbalancer entries
lm.loadBalancer = nil
return nil
}
//Stop - handles the building of the load balancers
func (l *LBInstance) Stop() error {
close(l.stop)
<-l.stopped
log.Infof("Load Balancer instance [%s] has stopped", l.instance.Name)
return nil
}

30
pkg/manager/cluster.go Normal file
View File

@@ -0,0 +1,30 @@
package manager
import (
"github.com/pkg/errors"
"github.com/kube-vip/kube-vip/pkg/cluster"
"github.com/kube-vip/kube-vip/pkg/etcd"
)
func initClusterManager(sm *Manager) (*cluster.Manager, error) {
m := &cluster.Manager{
SignalChan: sm.signalChan,
}
switch sm.config.LeaderElectionType {
case "kubernetes", "":
m.KubernetesClient = sm.clientSet
m.RetryWatcherClient = sm.rwClientSet
case "etcd":
client, err := etcd.NewClient(sm.config)
if err != nil {
return nil, err
}
m.EtcdClient = client
default:
return nil, errors.Errorf("invalid LeaderElectionMode %s not supported", sm.config.LeaderElectionType)
}
return m, nil
}

336
pkg/manager/manager.go Normal file
View File

@@ -0,0 +1,336 @@
package manager
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/arp"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/k8s"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/networkinterface"
"github.com/kube-vip/kube-vip/pkg/services"
"github.com/kube-vip/kube-vip/pkg/upnp"
"github.com/kube-vip/kube-vip/pkg/utils"
"github.com/prometheus/client_golang/prometheus"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
const plunderLock = "plndr-svcs-lock"
// Manager degines the manager of the load-balancing services
type Manager struct {
clientSet *kubernetes.Clientset
rwClientSet *kubernetes.Clientset
configMap string
config *kubevip.Config
// Manager services
// service bool
// BGP Manager, this is a singleton that manages all BGP advertisements
bgpServer *bgp.Server
// This channel is used to catch an OS signal and trigger a shutdown
signalChan chan os.Signal
// This channel is used to signal a shutdown
shutdownChan chan struct{}
svcProcessor *services.Processor
// This is a prometheus counter used to count the number of events received
// from the service watcher
countServiceWatchEvent *prometheus.CounterVec
// This is a prometheus gauge indicating the state of the sessions.
// 1 means "ESTABLISHED", 0 means "NOT ESTABLISHED"
bgpSessionInfoGauge *prometheus.GaugeVec
// This mutex is to protect calls from various goroutines
mutex sync.Mutex
// This tracks used network interfaces and guards them with mutex for concurrent changes.
intfMgr *networkinterface.Manager
// This tracks VIPs and performs ARP/NDP advertisement.
arpMgr *arp.Manager
}
// New will create a new managing object
func New(configMap string, config *kubevip.Config) (*Manager, error) {
// Instance identity should be the same as k8s node name to ensure better compatibility.
// By default k8s sets node name to `hostname -s`,
// so if node name is not provided in the config,
// we set it to hostname as a fallback.
// This mimics legacy behavior and should work on old kube-vip installations.
if config.NodeName == "" {
log.Warn("Node name is missing from the config, fall back to hostname")
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("could not get hostname: %v", err)
}
config.NodeName = hostname
}
log.Info("using node name", "name", config.NodeName)
adminConfigPath := "/etc/kubernetes/admin.conf"
homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config")
var clientset *kubernetes.Clientset
var clientConfig *rest.Config
var err error
switch {
case config.LeaderElectionType == "etcd":
// Do nothing, we don't construct a k8s client for etcd leader election
case utils.FileExists(adminConfigPath):
if config.KubernetesAddr != "" {
log.Info("k8s address", "address", config.KubernetesAddr)
clientConfig, err = k8s.NewRestConfig(adminConfigPath, false, config.KubernetesAddr)
} else if config.EnableControlPlane {
// If this is a control plane host it will likely have started as a static pod or won't have the
// VIP up before trying to connect to the API server, we set the API endpoint to this machine to
// ensure connectivity.
if config.DetectControlPlane {
clientConfig, err = k8s.FindWorkingKubernetesAddress(adminConfigPath, false)
} else {
// This will attempt to use kubernetes as the hostname (this should be passed as a host alias) in the pod manifest
clientConfig, err = k8s.NewRestConfig(adminConfigPath, false, fmt.Sprintf("kubernetes:%v", config.Port))
}
} else {
clientConfig, err = k8s.NewRestConfig(adminConfigPath, false, "")
}
if err != nil {
return nil, fmt.Errorf("could not create k8s REST config from external file: %q: %w", adminConfigPath, err)
}
if clientset, err = k8s.NewClientset(clientConfig); err != nil {
return nil, fmt.Errorf("could not create k8s clientset: %w", err)
}
log.Debug("Using external Kubernetes configuration from file", "path", adminConfigPath)
case utils.FileExists(homeConfigPath):
clientConfig, err = k8s.NewRestConfig(homeConfigPath, false, "")
if err != nil {
return nil, fmt.Errorf("could not create k8s REST config from external file: %q: %w", homeConfigPath, err)
}
clientset, err = k8s.NewClientset(clientConfig)
if err != nil {
return nil, fmt.Errorf("could not create k8s clientset from external file: %q: %w", homeConfigPath, err)
}
log.Debug("Using external Kubernetes configuration from file", "path", adminConfigPath)
default:
clientConfig, err = k8s.NewRestConfig("", true, "")
if err != nil {
return nil, fmt.Errorf("could not create k8s REST config from incluster file: %q: %w", homeConfigPath, err)
}
clientset, err = k8s.NewClientset(clientConfig)
if err != nil {
return nil, fmt.Errorf("could not create k8s clientset from incluster config: %w", err)
}
log.Debug("Using external Kubernetes configuration from incluster config.")
}
var rwClientSet *kubernetes.Clientset
// if clientConfig is not nil, then we are not using etcd leader election
// we need to create non-timeout clientset for RetryWatcher
if clientConfig != nil {
rwConfig := *clientConfig
rwConfig.Timeout = 0
rwClientSet, err = k8s.NewClientset(&rwConfig)
if err != nil {
return nil, fmt.Errorf("could not create k8s clientset for retry watcher: %w", err)
}
}
// Flip this to something else
// if config.DetectControlPlane {
// log.Info("[k8s client] flipping to internal service account")
// _, err = clientset.CoreV1().ServiceAccounts("kube-system").Apply(context.TODO(), kubevip.GenerateSA(), v1.ApplyOptions{FieldManager: "application/apply-patch"})
// if err != nil {
// return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err)
// }
// _, err = clientset.RbacV1().ClusterRoles().Apply(context.TODO(), kubevip.GenerateCR(), v1.ApplyOptions{FieldManager: "application/apply-patch"})
// if err != nil {
// return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err)
// }
// _, err = clientset.RbacV1().ClusterRoleBindings().Apply(context.TODO(), kubevip.GenerateCRB(), v1.ApplyOptions{FieldManager: "application/apply-patch"})
// if err != nil {
// return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err)
// }
// }
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
signalChan := make(chan os.Signal, 1)
// Add Notification for Userland interrupt
signal.Notify(signalChan, syscall.SIGINT)
// Add Notification for SIGTERM (sent from Kubernetes)
signal.Notify(signalChan, syscall.SIGTERM)
// All watchers and other goroutines should have an additional goroutine that blocks on this, to shut things down
shutdownChan := make(chan struct{})
intfMgr := networkinterface.NewManager()
arpMgr := arp.NewManager(config)
var bgpServer *bgp.Server
if config.EnableBGP {
bgpServer, err = bgp.NewBGPServer(&config.BGPConfig)
if err != nil {
return nil, fmt.Errorf("creating BGP server: %w", err)
}
}
svcProcessor := services.NewServicesProcessor(config, bgpServer, clientset, rwClientSet, shutdownChan, intfMgr, arpMgr)
return &Manager{
clientSet: clientset,
rwClientSet: rwClientSet,
configMap: configMap,
config: config,
countServiceWatchEvent: prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "kube_vip",
Subsystem: "manager",
Name: "all_services_events",
Help: "Count all events fired by the service watcher categorised by event type",
}, []string{"type"}),
bgpSessionInfoGauge: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "kube_vip",
Subsystem: "manager",
Name: "bgp_session_info",
Help: "Display state of session by setting metric for label value with current state to 1",
}, []string{"state", "peer"}),
signalChan: signalChan,
shutdownChan: shutdownChan,
svcProcessor: svcProcessor,
intfMgr: intfMgr,
arpMgr: arpMgr,
bgpServer: bgpServer,
}, nil
}
// Start will begin the Manager, which will start services and watch the configmap
func (sm *Manager) Start() error {
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
sm.signalChan = make(chan os.Signal, 1)
// Add Notification for Userland interrupt
signal.Notify(sm.signalChan, syscall.SIGINT)
// Add Notification for SIGTERM (sent from Kubernetes)
signal.Notify(sm.signalChan, syscall.SIGTERM)
// All watchers and other goroutines should have an additional goroutine that blocks on this, to shut things down
sm.shutdownChan = make(chan struct{})
// HealthCheck
if sm.config.HealthCheckPort != 0 {
if sm.config.HealthCheckPort < 1024 {
return fmt.Errorf("healthcheck port is using a port that is less than 1024 [%d]", sm.config.HealthCheckPort)
}
http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintf(w, "OK")
})
go func() {
server := &http.Server{
Addr: fmt.Sprintf(":%d", sm.config.HealthCheckPort),
ReadHeaderTimeout: 3 * time.Second,
}
err := server.ListenAndServe()
if err != nil {
log.Error("healthcheck", "unable to start", err)
}
}()
}
// If BGP is enabled then we start a server instance that will broadcast VIPs
if sm.config.EnableBGP {
// If Annotations have been set then we will look them up
err := sm.parseAnnotations()
if err != nil {
return err
}
log.Info("Starting Kube-vip Manager with the BGP engine")
return sm.startBGP()
}
if sm.config.EnableARP || sm.config.EnableWireguard {
if sm.config.EnableUPNP {
clients := upnp.GetConnectionClients(context.TODO())
if len(clients) == 0 {
log.Error("Error Enabling UPNP. No Clients found")
// Set the struct to false so nothing should use it in future
sm.config.EnableUPNP = false
} else {
for _, c := range clients {
ip, err := c.GetExternalIPAddress()
if err != nil {
log.Error("unable to find IGD2 Gateway address", "err", err)
}
log.Info("Found UPNP IGD2 Gateway address", "ip", ip)
}
}
}
// TODO: It would be nice to run the UPNP refresh only on the leader.
go sm.svcProcessor.RefreshUPNPForwards()
}
// If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs
if sm.config.EnableARP {
log.Info("Starting Kube-vip Manager with the ARP engine")
return sm.startARP(sm.config.NodeName)
}
if sm.config.EnableWireguard {
log.Info("Starting Kube-vip Manager with the Wireguard engine")
return sm.startWireguard(sm.config.NodeName)
}
if sm.config.EnableRoutingTable {
log.Info("Starting Kube-vip Manager with the Routing Table engine")
return sm.startTableMode(sm.config.NodeName)
}
log.Error("prematurely exiting Load-balancer as no modes [ARP/BGP/Wireguard] are enabled")
return nil
}
func returnNameSpace() (string, error) {
if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
if ns := strings.TrimSpace(string(data)); len(ns) > 0 {
return ns, nil
}
return "", err
}
return "", fmt.Errorf("unable to find Namespace")
}
func (sm *Manager) parseAnnotations() error {
if sm.config.Annotations == "" {
log.Debug("No Node annotations to parse")
return nil
}
err := sm.annotationsWatcher()
if err != nil {
return err
}
return nil
}

159
pkg/manager/manager_arp.go Normal file
View File

@@ -0,0 +1,159 @@
package manager
import (
"context"
"syscall"
"time"
log "log/slog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"github.com/kube-vip/kube-vip/pkg/cluster"
"github.com/kube-vip/kube-vip/pkg/iptables"
"github.com/kube-vip/kube-vip/pkg/vip"
)
// Start will begin the Manager, which will start services and watch the configmap
func (sm *Manager) startARP(id string) error {
var cpCluster *cluster.Cluster
var ns string
var err error
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.Info("Start ARP/NDP advertisement")
go sm.arpMgr.StartAdvertisement(ctx)
// Shutdown function that will wait on this signal, unless we call it ourselves
go func() {
<-sm.signalChan
log.Info("Received kube-vip termination, signaling shutdown")
if sm.config.EnableControlPlane {
cpCluster.Stop()
}
// Close all go routines
close(sm.shutdownChan)
// Cancel the context, which will in turn cancel the leadership
cancel()
}()
if sm.config.EnableControlPlane {
cpCluster, err = cluster.InitCluster(sm.config, false, sm.intfMgr, sm.arpMgr)
if err != nil {
return err
}
clusterManager, err := initClusterManager(sm)
if err != nil {
return err
}
go func() {
err := cpCluster.StartCluster(sm.config, clusterManager, nil)
if err != nil {
log.Error("starting control plane", "err", err)
// Trigger the shutdown of this manager instance
sm.signalChan <- syscall.SIGINT
}
}()
// Check if we're also starting the services, if not we can sit and wait on the closing channel and return here
if !sm.config.EnableServices {
<-sm.shutdownChan
log.Info("Shutting down Kube-Vip")
return nil
}
ns = sm.config.Namespace
} else {
ns, err = returnNameSpace()
if err != nil {
log.Warn("unable to auto-detect namespace, dropping to config", "namespace", sm.config.Namespace)
ns = sm.config.Namespace
}
}
// This will tidy any dangling kube-vip iptables rules
if sm.config.EgressClean {
vip.ClearIPTables(sm.config.EgressWithNftables, sm.config.ServiceNamespace, iptables.ProtocolIPv4)
}
// Start a services watcher (all kube-vip pods will watch services), upon a new service
// a lock based upon that service is created that they will all leaderElection on
if sm.config.EnableServicesElection {
log.Info("beginning watching services, leaderelection will happen for every service")
err = sm.svcProcessor.StartServicesWatchForLeaderElection(ctx)
if err != nil {
return err
}
} else {
log.Info("beginning services leadership", "namespace", ns, "lock name", sm.config.ServicesLeaseName, "id", id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Name: sm.config.ServicesLeaseName,
Namespace: ns,
},
Client: sm.clientSet.CoordinationV1(),
LockConfig: resourcelock.ResourceLockConfig{
Identity: id,
},
}
// start the leader election code loop
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
Lock: lock,
// IMPORTANT: you MUST ensure that any code you have that
// is protected by the lease must terminate **before**
// you call cancel. Otherwise, you could have a background
// loop still running and another process could
// get elected before your background loop finished, violating
// the stated goal of the lease.
ReleaseOnCancel: true,
LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second,
RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second,
RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
err = sm.svcProcessor.ServicesWatcher(ctx, sm.svcProcessor.SyncServices)
if err != nil {
log.Error("service watcher", "err", err)
panic("") // TODO: - emulating log.fatal here
}
},
OnStoppedLeading: func() {
// we can do cleanup here
sm.mutex.Lock()
defer sm.mutex.Unlock()
log.Info("leader lost", "new leader", id)
sm.svcProcessor.Stop()
log.Error("lost leadership, restarting kube-vip")
panic("") // TODO: - emulating log.fatal here
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
if sm.config.EnableNodeLabeling {
applyNodeLabel(sm.clientSet, sm.config.Address, id, identity)
}
if identity == id {
// I just got the lock
return
}
log.Info("new leader elected", "new leader", identity)
},
},
})
}
return nil
}

116
pkg/manager/manager_bgp.go Normal file
View File

@@ -0,0 +1,116 @@
package manager
import (
"context"
"fmt"
"syscall"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/cluster"
api "github.com/osrg/gobgp/v3/api"
"github.com/prometheus/client_golang/prometheus"
)
// Start will begin the Manager, which will start services and watch the configmap
func (sm *Manager) startBGP() error {
var cpCluster *cluster.Cluster
// var ns string
var err error
if sm.bgpServer == nil {
sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig)
if err != nil {
return fmt.Errorf("creating BGP server: %w", err)
}
}
log.Info("Starting the BGP server to advertise VIP routes to BGP peers")
if err := sm.bgpServer.Start(func(p *api.WatchEventResponse_PeerEvent) {
ipaddr := p.GetPeer().GetState().GetNeighborAddress()
port := uint64(179)
peerDescription := fmt.Sprintf("%s:%d", ipaddr, port)
for stateName, stateValue := range api.PeerState_SessionState_value {
metricValue := 0.0
if stateValue == int32(p.GetPeer().GetState().GetSessionState().Number()) {
metricValue = 1
}
sm.bgpSessionInfoGauge.With(prometheus.Labels{
"state": stateName,
"peer": peerDescription,
}).Set(metricValue)
}
}); err != nil {
return fmt.Errorf("starting BGP server: %w", err)
}
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Defer a function to check if the bgpServer has been created and if so attempt to close it
defer func() {
if sm.bgpServer != nil {
sm.bgpServer.Close()
}
}()
// Shutdown function that will wait on this signal, unless we call it ourselves
go func() {
<-sm.signalChan
log.Info("Received termination, signaling shutdown")
if sm.config.EnableControlPlane {
if cpCluster != nil {
cpCluster.Stop()
}
}
// Cancel the context, which will in turn cancel the leadership
cancel()
}()
if sm.config.EnableControlPlane {
cpCluster, err = cluster.InitCluster(sm.config, false, sm.intfMgr, sm.arpMgr)
if err != nil {
return err
}
clusterManager, err := initClusterManager(sm)
if err != nil {
return err
}
go func() {
if sm.config.EnableLeaderElection {
err = cpCluster.StartCluster(sm.config, clusterManager, sm.bgpServer)
} else {
err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer)
}
if err != nil {
log.Error("Control Plane", "err", err)
// Trigger the shutdown of this manager instance
sm.signalChan <- syscall.SIGINT
}
}()
// Check if we're also starting the services, if not we can sit and wait on the closing channel and return here
if !sm.config.EnableServices {
<-sm.signalChan
log.Info("Shutting down Kube-Vip")
return nil
}
}
err = sm.svcProcessor.ServicesWatcher(ctx, sm.svcProcessor.SyncServices)
if err != nil {
return err
}
log.Info("Shutting down Kube-Vip")
return nil
}

View File

@@ -0,0 +1,185 @@
package manager
import (
"context"
"fmt"
"syscall"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/cluster"
"github.com/kube-vip/kube-vip/pkg/endpoints"
"github.com/kube-vip/kube-vip/pkg/iptables"
"github.com/kube-vip/kube-vip/pkg/vip"
"github.com/vishvananda/netlink"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
)
// Start will begin the Manager, which will start services and watch the configmap
func (sm *Manager) startTableMode(id string) error {
var cpCluster *cluster.Cluster
var err error
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.Info("destination for routes", "table", sm.config.RoutingTableID, "protocol", sm.config.RoutingProtocol)
if sm.config.CleanRoutingTable {
go func() {
// we assume that after 10s all services should be configured so we can delete redundant routes
time.Sleep(time.Second * 10)
if err := sm.cleanRoutes(); err != nil {
log.Error("error checking for old routes", "err", err)
}
}()
}
if sm.config.EgressClean {
vip.ClearIPTables(sm.config.EgressWithNftables, sm.config.ServiceNamespace, iptables.ProtocolIPv4)
vip.ClearIPTables(sm.config.EgressWithNftables, sm.config.ServiceNamespace, iptables.ProtocolIPv6)
log.Debug("IPtables rules cleaned on startup")
}
// Shutdown function that will wait on this signal, unless we call it ourselves
go func() {
<-sm.signalChan
log.Info("Received kube-vip termination, signaling shutdown")
if sm.config.EnableControlPlane {
cpCluster.Stop()
}
// Cancel the context, which will in turn cancel the leadership
cancel()
}()
if sm.config.EnableControlPlane {
cpCluster, err = cluster.InitCluster(sm.config, false, sm.intfMgr, sm.arpMgr)
if err != nil {
return fmt.Errorf("cluster initialization error: %w", err)
}
clusterManager, err := initClusterManager(sm)
if err != nil {
return fmt.Errorf("cluster manager initialization error: %w", err)
}
if err := cpCluster.StartVipService(sm.config, clusterManager, nil); err != nil {
log.Error("Control Plane", "err", err)
// Trigger the shutdown of this manager instance
sm.signalChan <- syscall.SIGINT
}
} else {
ns, err := returnNameSpace()
if err != nil {
log.Warn("unable to auto-detect namespace", "dropping to", sm.config.Namespace)
ns = sm.config.Namespace
}
// Start a services watcher (all kube-vip pods will watch services), upon a new service
// a lock based upon that service is created that they will all leaderElection on
if sm.config.EnableServicesElection {
log.Info("beginning watching services, leaderelection will happen for every service")
err = sm.svcProcessor.StartServicesWatchForLeaderElection(ctx)
if err != nil {
return err
}
} else if sm.config.EnableLeaderElection {
log.Info("beginning services leadership", "namespace", ns, "lock name", plunderLock, "id", id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Name: plunderLock,
Namespace: ns,
},
Client: sm.clientSet.CoordinationV1(),
LockConfig: resourcelock.ResourceLockConfig{
Identity: id,
},
}
// start the leader election code loop
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
Lock: lock,
// IMPORTANT: you MUST ensure that any code you have that
// is protected by the lease must terminate **before**
// you call cancel. Otherwise, you could have a background
// loop still running and another process could
// get elected before your background loop finished, violating
// the stated goal of the lease.
ReleaseOnCancel: true,
LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second,
RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second,
RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
err = sm.svcProcessor.ServicesWatcher(ctx, sm.svcProcessor.SyncServices)
if err != nil {
log.Error(err.Error())
panic("")
}
},
OnStoppedLeading: func() {
// we can do cleanup here
sm.mutex.Lock()
defer sm.mutex.Unlock()
log.Info("leader lost", "id", id)
sm.svcProcessor.Stop()
log.Error("lost leadership, restarting kube-vip")
panic("")
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
if identity == id {
// I just got the lock
return
}
log.Info("new leader elected", "id", identity)
},
},
})
} else {
log.Info("beginning watching services without leader election")
err = sm.svcProcessor.ServicesWatcher(ctx, sm.svcProcessor.SyncServices)
if err != nil {
log.Error("Cannot watch services", "err", err)
}
}
}
return nil
}
func (sm *Manager) cleanRoutes() error {
sm.mutex.Lock()
defer sm.mutex.Unlock()
routes, err := vip.ListRoutes(sm.config.RoutingTableID, sm.config.RoutingProtocol)
if err != nil {
return fmt.Errorf("error getting routes: %w", err)
}
for i := range routes {
found := false
if sm.config.EnableControlPlane {
found = (routes[i].Dst.IP.String() == sm.config.Address)
} else {
found = endpoints.CountRouteReferences(&routes[i], &sm.svcProcessor.ServiceInstances) > 0
}
if !found {
err = netlink.RouteDel(&(routes[i]))
if err != nil {
log.Error("[route] deletion", "route", routes[i], "err", err)
}
log.Debug("[route] deletion", "route", routes[i])
}
}
return nil
}

View File

@@ -0,0 +1,122 @@
package manager
import (
"context"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/wireguard"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
)
// Start will begin the Manager, which will start services and watch the configmap
func (sm *Manager) startWireguard(id string) error {
var ns string
var err error
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.Info("reading wireguard peer configuration from Kubernetes secret")
s, err := sm.clientSet.CoreV1().Secrets(sm.config.Namespace).Get(ctx, "wireguard", metav1.GetOptions{})
if err != nil {
return err
}
// parse all the details needed for Wireguard
peerPublicKey := s.Data["peerPublicKey"]
peerEndpoint := s.Data["peerEndpoint"]
privateKey := s.Data["privateKey"]
// Configure the interface to join the Wireguard VPN
err = wireguard.ConfigureInterface(string(privateKey), string(peerPublicKey), string(peerEndpoint))
if err != nil {
return err
}
// Shutdown function that will wait on this signal, unless we call it ourselves
go func() {
<-sm.signalChan
log.Info("Received termination, signaling shutdown")
// Cancel the context, which will in turn cancel the leadership
cancel()
}()
ns, err = returnNameSpace()
if err != nil {
log.Warn("unable to auto-detect namespace", "dropping to", sm.config.Namespace)
ns = sm.config.Namespace
}
// Start a services watcher (all kube-vip pods will watch services), upon a new service
// a lock based upon that service is created that they will all leaderElection on
if sm.config.EnableServicesElection {
log.Info("beginning watching services, leaderelection will happen for every service")
err = sm.svcProcessor.StartServicesWatchForLeaderElection(ctx)
if err != nil {
return err
}
} else {
log.Info("beginning services leadership", "namespace", ns, "lock name", plunderLock, "id", id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Name: plunderLock,
Namespace: ns,
},
Client: sm.clientSet.CoordinationV1(),
LockConfig: resourcelock.ResourceLockConfig{
Identity: id,
},
}
// start the leader election code loop
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
Lock: lock,
// IMPORTANT: you MUST ensure that any code you have that
// is protected by the lease must terminate **before**
// you call cancel. Otherwise, you could have a background
// loop still running and another process could
// get elected before your background loop finished, violating
// the stated goal of the lease.
ReleaseOnCancel: true,
LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second,
RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second,
RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
err = sm.svcProcessor.ServicesWatcher(ctx, sm.svcProcessor.SyncServices)
if err != nil {
log.Error(err.Error())
panic("")
}
},
OnStoppedLeading: func() {
// we can do cleanup here
sm.mutex.Lock()
defer sm.mutex.Unlock()
log.Info("leader lost", "id", id)
sm.svcProcessor.Stop()
log.Error("lost leadership, restarting kube-vip")
panic("")
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
if identity == id {
// I just got the lock
return
}
log.Info("new leader elected", "id", identity)
},
},
})
}
return nil
}

View File

@@ -0,0 +1,73 @@
package manager
import (
"context"
"encoding/json"
"fmt"
log "log/slog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
)
const (
nodeLabelIndex = "kube-vip.io/has-ip"
nodeLabelJSONPath = `kube-vip.io~1has-ip`
)
type patchStringLabel struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value"`
}
// applyNodeLabel add/remove node label `kube-vip.io/has-ip=<VIP-Address>` to/from
// the node where the virtual IP was added to/removed from.
func applyNodeLabel(clientSet *kubernetes.Clientset, address, id, identity string) {
ctx := context.Background()
node, err := clientSet.CoreV1().Nodes().Get(ctx, id, metav1.GetOptions{})
if err != nil {
log.Error("can't query node labels", "node", id, "err", err)
return
}
log.Debug(fmt.Sprintf("node %s labels: %+v", id, node.Labels))
value, ok := node.Labels[nodeLabelIndex]
path := fmt.Sprintf("/metadata/labels/%s", nodeLabelJSONPath)
log.Debug(fmt.Sprintf("Received identity: %s - id: %s", identity, id))
if ok && value == address {
log.Debug(fmt.Sprintf("removing node label `has-ip=%s` on %s", address, id))
// Remove label
applyPatchLabels(ctx, clientSet, id, "remove", path, address)
} else {
log.Debug(fmt.Sprintf("setting node label `has-ip=%s` on %s", address, id))
// Append label
applyPatchLabels(ctx, clientSet, id, "add", path, address)
}
}
// applyPatchLabels add/remove node labels
func applyPatchLabels(ctx context.Context, clientSet *kubernetes.Clientset,
name, operation, path, value string) {
patchLabels := []patchStringLabel{{
Op: operation,
Path: path,
Value: value,
}}
patchData, err := json.Marshal(patchLabels)
if err != nil {
log.Error("node patch marshaling failed", "err", err)
return
}
// patch node
node, err := clientSet.CoreV1().Nodes().Patch(ctx,
name, types.JSONPatchType, patchData, metav1.PatchOptions{})
if err != nil {
log.Error("node patching failed", "err", err)
return
}
log.Debug("updated", "node", name, "labels", node.Labels)
}

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