Compare commits

..

53 Commits

Author SHA1 Message Date
semantic-release-bot
a9bb22f16c release(rc): v1.3.2-rc.3
## [1.3.2-rc.3](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.2-rc.2...v1.3.2-rc.3) (2024-08-20)

### Build system and dependencies

* **deps:** update all non-major dependencies ([65f30a6](65f30a6b09))
2024-08-20 21:18:09 +00:00
65f30a6b09 build(deps): update all non-major dependencies
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-08-20 21:15:17 +00:00
semantic-release-bot
c269e64231 release(rc): v1.3.2-rc.2
## [1.3.2-rc.2](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.2-rc.1...v1.3.2-rc.2) (2024-08-20)

### Build system and dependencies

* **deps:** update golang docker tag to v1.23 ([0ad5148](0ad514865c))
2024-08-20 20:46:31 +00:00
0ad514865c
build(deps): update golang docker tag to v1.23
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-08-20 22:45:44 +02:00
semantic-release-bot
8f8d6eb47f release(rc): v1.3.2-rc.1
## [1.3.2-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1...v1.3.2-rc.1) (2024-08-20)

### Build system and dependencies

* **deps:** update all major dependencies ([48aa72b](48aa72b375))
2024-08-20 20:36:05 +00:00
48aa72b375 build(deps): update all major dependencies
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-06-01 00:02:40 +00:00
semantic-release-bot
7f5d2fd5e2 release(stable): v1.3.1
## [1.3.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.0...v1.3.1) (2024-05-27)

### Refactoring

* **formatting:** change line terminators from CRLF to LF ([ec44d7f](ec44d7f643))
* **probes:** rename `ProbeFunction` to `Probe` ([8dc7f27](8dc7f27400))

### Continuous Integrations

* **deps:** pin `conventional-changelog-conventionalcommits` to version 7.x ([b15846a](b15846aa58))
* **test:** remove `group` directive ([a1bab99](a1bab99cbd))

### Build system and dependencies

* **deps:** update all non-major dependencies ([a68663c](a68663cff0))
* **deps:** update dependency @semantic-release/commit-analyzer to v12 ([2a79a68](2a79a6878f))
* **deps:** update dependency @semantic-release/npm to v12 ([fdee33a](fdee33a1e7))
* **deps:** update dependency @semantic-release/release-notes-generator to v13 ([0cba4d2](0cba4d2a50))
* **deps:** update dependency conventional-changelog-conventionalcommits to v8 ([8918072](8918072d5c))
* **deps:** update dependency semantic-release to v23.0.3 ([cea539f](cea539fd6d))
* **deps:** update dependency semantic-release to v23.0.4 ([2d5b101](2d5b101b8d))
* **deps:** update dependency semantic-release to v23.0.5 ([061100e](061100e432))
* **deps:** update dependency semantic-release to v23.0.8 ([b98f6ef](b98f6ef609))
2024-05-27 23:55:53 +00:00
semantic-release-bot
e830e25560 release(rc): v1.3.1-rc.11
All checks were successful
ci/woodpecker/push/release Pipeline was successful
## [1.3.1-rc.11](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.10...v1.3.1-rc.11) (2024-05-27)

### Refactoring

* **formatting:** change line terminators from CRLF to LF ([ec44d7f](ec44d7f643))
2024-05-27 23:54:51 +00:00
ec44d7f643
refactor(formatting): change line terminators from CRLF to LF
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-05-28 01:54:25 +02:00
df80db0e29
docs(readme): add badges 2024-05-28 01:54:24 +02:00
semantic-release-bot
c8471ec264 release(rc): v1.3.1-rc.10
## [1.3.1-rc.10](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.9...v1.3.1-rc.10) (2024-05-27)

### Continuous Integrations

* **test:** remove `group` directive ([a1bab99](a1bab99cbd))
2024-05-27 23:49:39 +00:00
7a54da4c57
docs(readme): update README.md
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-05-28 01:43:09 +02:00
a1bab99cbd
ci(test): remove group directive 2024-05-28 01:39:29 +02:00
semantic-release-bot
eeb0d8f522 release(rc): v1.3.1-rc.9
## [1.3.1-rc.9](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.8...v1.3.1-rc.9) (2024-05-21)

### Continuous Integrations

* **deps:** pin `conventional-changelog-conventionalcommits` to version 7.x ([b15846a](b15846aa58))

### Build system and dependencies

* **deps:** update all non-major dependencies ([a68663c](a68663cff0))
* **deps:** update dependency conventional-changelog-conventionalcommits to v8 ([8918072](8918072d5c))
2024-05-21 21:01:49 +00:00
b15846aa58
ci(deps): pin conventional-changelog-conventionalcommits to version 7.x
All checks were successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
2024-05-21 23:00:55 +02:00
a68663cff0 build(deps): update all non-major dependencies
Some checks failed
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline failed
ci/woodpecker/push/test Pipeline was successful
2024-05-15 13:15:19 +02:00
8918072d5c build(deps): update dependency conventional-changelog-conventionalcommits to v8
Some checks failed
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline failed
ci/woodpecker/push/test Pipeline was successful
2024-05-04 00:02:17 +00:00
semantic-release-bot
71c370f53a release(rc): v1.3.1-rc.8
## [1.3.1-rc.8](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.7...v1.3.1-rc.8) (2024-04-12)

### Build system and dependencies

* **deps:** update dependency semantic-release to v23.0.8 ([b98f6ef](b98f6ef609))
2024-04-12 12:44:11 +00:00
b98f6ef609 build(deps): update dependency semantic-release to v23.0.8
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-04-12 12:41:33 +00:00
semantic-release-bot
16f29ebfc1 release(rc): v1.3.1-rc.7
## [1.3.1-rc.7](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.6...v1.3.1-rc.7) (2024-04-12)

### Build system and dependencies

* **deps:** update dependency @semantic-release/release-notes-generator to v13 ([0cba4d2](0cba4d2a50))
2024-04-12 12:39:03 +00:00
0cba4d2a50 build(deps): update dependency @semantic-release/release-notes-generator to v13
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
2024-03-27 00:02:50 +00:00
semantic-release-bot
b441b35d48 release(rc): v1.3.1-rc.6
## [1.3.1-rc.6](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.5...v1.3.1-rc.6) (2024-03-23)

### Build system and dependencies

* **deps:** update dependency semantic-release to v23.0.5 ([061100e](061100e432))
2024-03-23 23:21:53 +00:00
061100e432 build(deps): update dependency semantic-release to v23.0.5
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-03-23 23:20:30 +00:00
semantic-release-bot
9288fcd144 release(rc): v1.3.1-rc.5
## [1.3.1-rc.5](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.4...v1.3.1-rc.5) (2024-03-23)

### Build system and dependencies

* **deps:** update dependency @semantic-release/commit-analyzer to v12 ([2a79a68](2a79a6878f))
2024-03-23 23:18:28 +00:00
2a79a6878f build(deps): update dependency @semantic-release/commit-analyzer to v12
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-03-19 00:02:43 +00:00
semantic-release-bot
d0a17892a1 release(rc): v1.3.1-rc.4
## [1.3.1-rc.4](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.3...v1.3.1-rc.4) (2024-03-17)

### Build system and dependencies

* **deps:** update dependency @semantic-release/npm to v12 ([fdee33a](fdee33a1e7))
2024-03-17 11:36:51 +00:00
fdee33a1e7 build(deps): update dependency @semantic-release/npm to v12
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-03-17 11:34:40 +00:00
semantic-release-bot
d89fd7fdd7 release(rc): v1.3.1-rc.3
## [1.3.1-rc.3](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.2...v1.3.1-rc.3) (2024-03-17)

### Build system and dependencies

* **deps:** update dependency semantic-release to v23.0.4 ([2d5b101](2d5b101b8d))
2024-03-17 11:31:08 +00:00
2d5b101b8d build(deps): update dependency semantic-release to v23.0.4
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-03-17 00:02:45 +00:00
semantic-release-bot
100c32969f release(rc): v1.3.1-rc.2
## [1.3.1-rc.2](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.1...v1.3.1-rc.2) (2024-03-16)

### Build system and dependencies

* **deps:** update dependency semantic-release to v23.0.3 ([cea539f](cea539fd6d))
2024-03-16 00:06:53 +00:00
cea539fd6d build(deps): update dependency semantic-release to v23.0.3
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-03-16 00:03:37 +00:00
semantic-release-bot
2a779b10db release(rc): v1.3.1-rc.1
## [1.3.1-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.0...v1.3.1-rc.1) (2024-03-03)

### Refactoring

* **probes:** rename `ProbeFunction` to `Probe` ([8dc7f27](8dc7f27400))
2024-03-03 22:27:55 +00:00
8dc7f27400
refactor(probes): rename ProbeFunction to Probe
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
2024-03-03 23:25:56 +01:00
semantic-release-bot
24cb5d816a release(stable): v1.3.0
## [1.3.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.0...v1.3.0) (2024-03-02)

### ⚠ BREAKING CHANGES

* **probes:** type definitions were replaced with more robust implementation.

### Features

* **probes:** rewrite probes logic with named probes ([9dd25ff](9dd25ff024))
* **validation:** add empty probe lists validation ([82b6034](82b6034625))

### Refactoring

* **names:** refactor handler fetching methods' names ([373c803](373c803c00))
* **validation:** improve errors joining ([ea92b29](ea92b2979c))

### Build system and dependencies

* **deps:** update dependency @semantic-release/npm to v11.0.3 ([203180c](203180c332))
2024-03-02 23:07:59 +00:00
semantic-release-bot
28a77b3731 release(rc): v1.3.0-rc.2
All checks were successful
ci/woodpecker/push/release Pipeline was successful
## [1.3.0-rc.2](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.0-rc.1...v1.3.0-rc.2) (2024-03-02)

### ⚠ BREAKING CHANGES

* **probes:** type definitions were replaced with more robust implementation.

### Features

* **probes:** rewrite probes logic with named probes ([9dd25ff](9dd25ff024))
2024-03-02 23:06:30 +00:00
ff3db1ea10 Merge pull request 'feat(probes)!: rewrite probes logic with named probes' (#9) from naming into devel
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Reviewed-on: #9
2024-03-03 00:06:04 +01:00
9dd25ff024
feat(probes)!: rewrite probes logic with named probes
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
- `ProbeFunction` is now an interface for easier use
- `ProbeFunction`s can be auto-updated with specified update interval
- `StatefulProbes` changed into `ManualProbes` and implement `ProbeFunction` interface
- `ManualProbes` allows for marking probe as unhealthy with custom cause
- handlers now return JSON response with failed probes
- handler's response can be set to verbose via `Kubeprobes` option or via `?v` request param

BREAKING CHANGE: type definitions were replaced with more robust implementation.
2024-03-03 00:00:57 +01:00
semantic-release-bot
71f7e9e7df release(rc): v1.3.0-rc.1
## [1.3.0-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.1-rc.1...v1.3.0-rc.1) (2024-03-02)

### Features

* **validation:** add empty probe lists validation ([82b6034](82b6034625))

### Refactoring

* **names:** refactor handler fetching methods' names ([373c803](373c803c00))
* **validation:** improve errors joining ([ea92b29](ea92b2979c))
2024-03-02 15:30:51 +00:00
aed7fec97d Merge pull request 'Code suggestions' (#8) from refactor into devel
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Reviewed-on: #8
2024-03-02 16:30:26 +01:00
ab8b7e84e2 tests(validation): add validation tests
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
2024-03-02 16:28:34 +01:00
82b6034625 feat(validation): add empty probe lists validation 2024-03-02 16:28:34 +01:00
ea92b2979c refactor(validation): improve errors joining 2024-03-02 16:28:34 +01:00
373c803c00 refactor(names): refactor handler fetching methods' names 2024-03-02 16:28:34 +01:00
semantic-release-bot
ec53b2851f release(rc): v1.2.1-rc.1
## [1.2.1-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.0...v1.2.1-rc.1) (2024-03-02)

### Build system and dependencies

* **deps:** update dependency @semantic-release/npm to v11.0.3 ([203180c](203180c332))
2024-03-02 15:16:45 +00:00
70aa6cd44c Merge pull request 'build(deps): update dependency @semantic-release/npm to v11.0.3' (#7) from renovate-all-minor-patch into devel
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Reviewed-on: #7
2024-03-02 16:16:20 +01:00
203180c332 build(deps): update dependency @semantic-release/npm to v11.0.3
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
2024-03-02 00:02:38 +00:00
semantic-release-bot
ba1170198c release(stable): v1.2.0
## [1.2.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.1.0...v1.2.0) (2024-03-01)

### Features

* **handlers:** add individual handlers fetching ([bb108ad](bb108ad9ba))

### Refactoring

* **kubeprobes:** refactor code ([d33e9f1](d33e9f19ea))
2024-03-01 22:50:45 +00:00
semantic-release-bot
b906789967 release(rc): v1.2.0-rc.1
All checks were successful
ci/woodpecker/push/release Pipeline was successful
## [1.2.0-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.1.0...v1.2.0-rc.1) (2024-03-01)

### Features

* **handlers:** add individual handlers fetching ([bb108ad](bb108ad9ba))

### Refactoring

* **kubeprobes:** refactor code ([d33e9f1](d33e9f19ea))
2024-03-01 22:46:27 +00:00
25962571c2 Merge pull request 'Major enhancements' (#6) from enhancements into devel
All checks were successful
ci/woodpecker/push/release Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Reviewed-on: #6
2024-03-01 23:46:03 +01:00
d6beb81938
docs(kubeprobes): update README
All checks were successful
ci/woodpecker/pr/test Pipeline was successful
2024-03-01 23:43:53 +01:00
bb108ad9ba
feat(handlers): add individual handlers fetching 2024-03-01 23:38:04 +01:00
d33e9f19ea
refactor(kubeprobes): refactor code
- refactored types, interfaces, options etc.
- added new options dedicated for `StatefulProbe`s
2024-03-01 23:32:11 +01:00
semantic-release-bot
429db2d8ed release(stable): v1.1.0
## [1.1.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.0.0...v1.1.0) (2024-02-29)

### Features

* **handler:** change path resolver logic ([40bad6b](40bad6b345))

### Continuous Integrations

* **init:** add initial CI configuration ([0db0e61](0db0e614d6))
* **renovate:** add Renovate bot configuration ([f5303b8](f5303b85fc))

### Build system and dependencies

* **deps:** update all non-major dependencies ([288033e](288033efd0))
* **deps:** update dependency semantic-release to v23 ([213039e](213039eaae))
2024-02-29 00:26:18 +00:00
20 changed files with 3046 additions and 1702 deletions

View File

@ -5,7 +5,6 @@ when:
steps:
test:
group: test
image: golang:1.22-alpine
image: golang:1.23-alpine
commands:
- go test -v ./...

View File

@ -1,3 +1,228 @@
## [1.3.2-rc.3](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.2-rc.2...v1.3.2-rc.3) (2024-08-20)
### Build system and dependencies
* **deps:** update all non-major dependencies ([65f30a6](https://git.ext.icikowski.pl/go/kubeprobes/commit/65f30a6b09628b6e58f40318279e2034f92790ba))
## [1.3.2-rc.2](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.2-rc.1...v1.3.2-rc.2) (2024-08-20)
### Build system and dependencies
* **deps:** update golang docker tag to v1.23 ([0ad5148](https://git.ext.icikowski.pl/go/kubeprobes/commit/0ad514865ca927f9f87747b2710f6be9f8b43590))
## [1.3.2-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1...v1.3.2-rc.1) (2024-08-20)
### Build system and dependencies
* **deps:** update all major dependencies ([48aa72b](https://git.ext.icikowski.pl/go/kubeprobes/commit/48aa72b3757830fb05ed136765cb7389ba1d7285))
## [1.3.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.0...v1.3.1) (2024-05-27)
### Refactoring
* **formatting:** change line terminators from CRLF to LF ([ec44d7f](https://git.ext.icikowski.pl/go/kubeprobes/commit/ec44d7f643e78cfb1e9724b36416458782a6c775))
* **probes:** rename `ProbeFunction` to `Probe` ([8dc7f27](https://git.ext.icikowski.pl/go/kubeprobes/commit/8dc7f27400075fabca9525f42eb20404736fb1cb))
### Continuous Integrations
* **deps:** pin `conventional-changelog-conventionalcommits` to version 7.x ([b15846a](https://git.ext.icikowski.pl/go/kubeprobes/commit/b15846aa58864f5809e2226cad9c52770f84aae9))
* **test:** remove `group` directive ([a1bab99](https://git.ext.icikowski.pl/go/kubeprobes/commit/a1bab99cbdbf903256be3172036fc9b8c44f9992))
### Build system and dependencies
* **deps:** update all non-major dependencies ([a68663c](https://git.ext.icikowski.pl/go/kubeprobes/commit/a68663cff022fa135d48fae6f00e39ea684983f1))
* **deps:** update dependency @semantic-release/commit-analyzer to v12 ([2a79a68](https://git.ext.icikowski.pl/go/kubeprobes/commit/2a79a6878f647049ca2f01711d74561f6c4974c6))
* **deps:** update dependency @semantic-release/npm to v12 ([fdee33a](https://git.ext.icikowski.pl/go/kubeprobes/commit/fdee33a1e7c05bd19f0f5d675df434ad4d844911))
* **deps:** update dependency @semantic-release/release-notes-generator to v13 ([0cba4d2](https://git.ext.icikowski.pl/go/kubeprobes/commit/0cba4d2a50319cc0250dc3cb14e32dee813b4fc0))
* **deps:** update dependency conventional-changelog-conventionalcommits to v8 ([8918072](https://git.ext.icikowski.pl/go/kubeprobes/commit/8918072d5c818bad10542957b93440730d50baf1))
* **deps:** update dependency semantic-release to v23.0.3 ([cea539f](https://git.ext.icikowski.pl/go/kubeprobes/commit/cea539fd6d68608635ec19ae8840da749695bfac))
* **deps:** update dependency semantic-release to v23.0.4 ([2d5b101](https://git.ext.icikowski.pl/go/kubeprobes/commit/2d5b101b8d38d7af7c6b4ba570f1045fe9e9dc7b))
* **deps:** update dependency semantic-release to v23.0.5 ([061100e](https://git.ext.icikowski.pl/go/kubeprobes/commit/061100e432a61ed6bcb310de297880db369e2f24))
* **deps:** update dependency semantic-release to v23.0.8 ([b98f6ef](https://git.ext.icikowski.pl/go/kubeprobes/commit/b98f6ef609c278bfbd25c25316ad166fba75f255))
## [1.3.1-rc.11](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.10...v1.3.1-rc.11) (2024-05-27)
### Refactoring
* **formatting:** change line terminators from CRLF to LF ([ec44d7f](https://git.ext.icikowski.pl/go/kubeprobes/commit/ec44d7f643e78cfb1e9724b36416458782a6c775))
## [1.3.1-rc.10](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.9...v1.3.1-rc.10) (2024-05-27)
### Continuous Integrations
* **test:** remove `group` directive ([a1bab99](https://git.ext.icikowski.pl/go/kubeprobes/commit/a1bab99cbdbf903256be3172036fc9b8c44f9992))
## [1.3.1-rc.9](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.8...v1.3.1-rc.9) (2024-05-21)
### Continuous Integrations
* **deps:** pin `conventional-changelog-conventionalcommits` to version 7.x ([b15846a](https://git.ext.icikowski.pl/go/kubeprobes/commit/b15846aa58864f5809e2226cad9c52770f84aae9))
### Build system and dependencies
* **deps:** update all non-major dependencies ([a68663c](https://git.ext.icikowski.pl/go/kubeprobes/commit/a68663cff022fa135d48fae6f00e39ea684983f1))
* **deps:** update dependency conventional-changelog-conventionalcommits to v8 ([8918072](https://git.ext.icikowski.pl/go/kubeprobes/commit/8918072d5c818bad10542957b93440730d50baf1))
## [1.3.1-rc.8](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.7...v1.3.1-rc.8) (2024-04-12)
### Build system and dependencies
* **deps:** update dependency semantic-release to v23.0.8 ([b98f6ef](https://git.ext.icikowski.pl/go/kubeprobes/commit/b98f6ef609c278bfbd25c25316ad166fba75f255))
## [1.3.1-rc.7](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.6...v1.3.1-rc.7) (2024-04-12)
### Build system and dependencies
* **deps:** update dependency @semantic-release/release-notes-generator to v13 ([0cba4d2](https://git.ext.icikowski.pl/go/kubeprobes/commit/0cba4d2a50319cc0250dc3cb14e32dee813b4fc0))
## [1.3.1-rc.6](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.5...v1.3.1-rc.6) (2024-03-23)
### Build system and dependencies
* **deps:** update dependency semantic-release to v23.0.5 ([061100e](https://git.ext.icikowski.pl/go/kubeprobes/commit/061100e432a61ed6bcb310de297880db369e2f24))
## [1.3.1-rc.5](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.4...v1.3.1-rc.5) (2024-03-23)
### Build system and dependencies
* **deps:** update dependency @semantic-release/commit-analyzer to v12 ([2a79a68](https://git.ext.icikowski.pl/go/kubeprobes/commit/2a79a6878f647049ca2f01711d74561f6c4974c6))
## [1.3.1-rc.4](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.3...v1.3.1-rc.4) (2024-03-17)
### Build system and dependencies
* **deps:** update dependency @semantic-release/npm to v12 ([fdee33a](https://git.ext.icikowski.pl/go/kubeprobes/commit/fdee33a1e7c05bd19f0f5d675df434ad4d844911))
## [1.3.1-rc.3](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.2...v1.3.1-rc.3) (2024-03-17)
### Build system and dependencies
* **deps:** update dependency semantic-release to v23.0.4 ([2d5b101](https://git.ext.icikowski.pl/go/kubeprobes/commit/2d5b101b8d38d7af7c6b4ba570f1045fe9e9dc7b))
## [1.3.1-rc.2](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.1-rc.1...v1.3.1-rc.2) (2024-03-16)
### Build system and dependencies
* **deps:** update dependency semantic-release to v23.0.3 ([cea539f](https://git.ext.icikowski.pl/go/kubeprobes/commit/cea539fd6d68608635ec19ae8840da749695bfac))
## [1.3.1-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.0...v1.3.1-rc.1) (2024-03-03)
### Refactoring
* **probes:** rename `ProbeFunction` to `Probe` ([8dc7f27](https://git.ext.icikowski.pl/go/kubeprobes/commit/8dc7f27400075fabca9525f42eb20404736fb1cb))
## [1.3.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.0...v1.3.0) (2024-03-02)
### ⚠ BREAKING CHANGES
* **probes:** type definitions were replaced with more robust implementation.
### Features
* **probes:** rewrite probes logic with named probes ([9dd25ff](https://git.ext.icikowski.pl/go/kubeprobes/commit/9dd25ff02437490dca537ac1d3c3baf71c4b6208))
* **validation:** add empty probe lists validation ([82b6034](https://git.ext.icikowski.pl/go/kubeprobes/commit/82b6034625089450d3de734edd8eb95ea35aff2f))
### Refactoring
* **names:** refactor handler fetching methods' names ([373c803](https://git.ext.icikowski.pl/go/kubeprobes/commit/373c803c00499a7e607cdd0ad99315dcd6e2919d))
* **validation:** improve errors joining ([ea92b29](https://git.ext.icikowski.pl/go/kubeprobes/commit/ea92b2979cbdb67507d934725434f21b0456be03))
### Build system and dependencies
* **deps:** update dependency @semantic-release/npm to v11.0.3 ([203180c](https://git.ext.icikowski.pl/go/kubeprobes/commit/203180c3329ff6a5d19258d425f40b60a79429dd))
## [1.3.0-rc.2](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.3.0-rc.1...v1.3.0-rc.2) (2024-03-02)
### ⚠ BREAKING CHANGES
* **probes:** type definitions were replaced with more robust implementation.
### Features
* **probes:** rewrite probes logic with named probes ([9dd25ff](https://git.ext.icikowski.pl/go/kubeprobes/commit/9dd25ff02437490dca537ac1d3c3baf71c4b6208))
## [1.3.0-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.1-rc.1...v1.3.0-rc.1) (2024-03-02)
### Features
* **validation:** add empty probe lists validation ([82b6034](https://git.ext.icikowski.pl/go/kubeprobes/commit/82b6034625089450d3de734edd8eb95ea35aff2f))
### Refactoring
* **names:** refactor handler fetching methods' names ([373c803](https://git.ext.icikowski.pl/go/kubeprobes/commit/373c803c00499a7e607cdd0ad99315dcd6e2919d))
* **validation:** improve errors joining ([ea92b29](https://git.ext.icikowski.pl/go/kubeprobes/commit/ea92b2979cbdb67507d934725434f21b0456be03))
## [1.2.1-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.0...v1.2.1-rc.1) (2024-03-02)
### Build system and dependencies
* **deps:** update dependency @semantic-release/npm to v11.0.3 ([203180c](https://git.ext.icikowski.pl/go/kubeprobes/commit/203180c3329ff6a5d19258d425f40b60a79429dd))
## [1.2.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.1.0...v1.2.0) (2024-03-01)
### Features
* **handlers:** add individual handlers fetching ([bb108ad](https://git.ext.icikowski.pl/go/kubeprobes/commit/bb108ad9baf7a14c7e39709a58987706a713d4ce))
### Refactoring
* **kubeprobes:** refactor code ([d33e9f1](https://git.ext.icikowski.pl/go/kubeprobes/commit/d33e9f19ea353cd320d584ad093c311f66eb1b28))
## [1.2.0-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.1.0...v1.2.0-rc.1) (2024-03-01)
### Features
* **handlers:** add individual handlers fetching ([bb108ad](https://git.ext.icikowski.pl/go/kubeprobes/commit/bb108ad9baf7a14c7e39709a58987706a713d4ce))
### Refactoring
* **kubeprobes:** refactor code ([d33e9f1](https://git.ext.icikowski.pl/go/kubeprobes/commit/d33e9f19ea353cd320d584ad093c311f66eb1b28))
## [1.1.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.0.0...v1.1.0) (2024-02-29)
### Features
* **handler:** change path resolver logic ([40bad6b](https://git.ext.icikowski.pl/go/kubeprobes/commit/40bad6b3456afaf9a7d04fb0af3911f47ffd601b))
### Continuous Integrations
* **init:** add initial CI configuration ([0db0e61](https://git.ext.icikowski.pl/go/kubeprobes/commit/0db0e614d6e6ae31b12b8629e5adaa3230bdbc45))
* **renovate:** add Renovate bot configuration ([f5303b8](https://git.ext.icikowski.pl/go/kubeprobes/commit/f5303b85fce436d9d8114b72dee8f4b44f332c55))
### Build system and dependencies
* **deps:** update all non-major dependencies ([288033e](https://git.ext.icikowski.pl/go/kubeprobes/commit/288033efd050b13e877e26682c1bef8e269b2988))
* **deps:** update dependency semantic-release to v23 ([213039e](https://git.ext.icikowski.pl/go/kubeprobes/commit/213039eaae78fce6734455ef379d492e799bc07f))
## [1.1.0-rc.1](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.0.1-rc.1...v1.1.0-rc.1) (2024-02-29)

106
README.md
View File

@ -1,5 +1,7 @@
# kubeprobes
[![Go Report Card](https://goreportcard.com/badge/pkg.icikowski.pl/kubeprobes)](https://goreportcard.com/report/pkg.icikowski.pl/kubeprobes)
Simple and effective package for implementing [Kubernetes liveness and readiness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)' handler.
## Installation
@ -10,77 +12,119 @@ go get -u pkg.icikowski.pl/kubeprobes
## Usage
The package provides `kubeprobes.New` function which returns a probes handler compliant with `http.Handler` interface.
The package provides `kubeprobes.New` function which returns a probes handler of type `kubeprobes.Kubeprobes`, which is compliant with `http.Handler` interface.
The handler serves two endpoints, which are used to implement liveness and readiness probes by returning either `200` (healthy) or `503` (unhealthy) status:
The handler serves two endpoints, which are used to implement liveness and readiness probes by returning either `200` (healthy) or `503` (unhealthy) status and JSON response with probes results:
- `/live` - endpoint for liveness probe;
- `/ready` - endpoint for readiness probe.
Accessing any other endpoint will return `404` status. In order to provide maximum performance, no body is ever returned.
Default paths can be overriden with options described below. Accessing any other endpoint will return `404` status. By default, response body only contains a list of failed probes, but this behavior can be changed with provided option or by adding `?v` query parameter.
The `kubeprobes.New` function accepts following options-applying functions as arguments:
The `kubeprobes.New` function accepts following options as arguments:
- `kubeprobes.WithLivenessProbes(/* ... */)` - adds particular [probes](#probes) to the list of liveness probes;
- `kubeprobes.WithReadinessProbes(/* ... */)` - adds particular [probes](#probes) to the list of readiness probes.
- `kubeprobes.WithLivenessProbes(...)` - adds particular [probes](#probes) to the list of liveness probes;
- `kubeprobes.WithLivenessPath("/some/liveness/path")` - sets liveness probe path to given path (default is `/live`);
- `kubeprobes.WithReadinessProbes(...)` - adds particular [probes](#probes) to the list of readiness probes;
- `kubeprobes.WithReadinessPath("/some/readiness/path")` - sets readiness probe path to given path (default is `/ready`);
- `kubeprobes.WithVerboseOutput()` - enables verbose output by default (returns both failed and passed probes).
## Probes
In order to determine the state of particular element of application, probes need to be implemented either by creating [status determining function](#probe-functions) or by using simple and thread-safe [stateful probes](#stateful-probes).
In order to determine the state of particular element of application, probes need to be implemented either by creating [probes from functions](#standard-probes) or by using simple and thread-safe [manual probes](#manual-probes).
### Probe functions
### Standard probes
Probe functions (objects of type `ProbeFunction`) are functions that performs user defined logic in order to determine whether the probe should be marked as healthy or not. Those functions should take no arguments and return error (if no error is returned, the probe is considered to be healthy; if error is returned, the probe is considered to be unhealthy).
Probes (instances of `Probe` interface) are wrappers for functions that performs user defined logic with given interval of updates in order to determine whether the probe should be marked as healthy or not. Those functions should take no arguments and return error (if no error is returned, the probe is considered to be healthy; if error is returned, the probe is considered to be unhealthy). If given interval is less or equal zero, then function is only checked on probe creation and remains in determined state forever.
```go
someProbe := func() error {
someProbe := kubeprobes.NewProbe("live", func() error {
// Some logic here
if somethingIsWrong {
return errors.New("something is wrong")
if time.Now().Weekday() == time.Wednesday {
// Fail only on wednesday!
return errors.New("It's wednesday, my dudes!")
}
return nil
}
}, 1 * time.Hour)
someOtherProbe := func() error {
someOtherProbe := kubeprobes.NewProbe("ready", func() error {
// Always healthy
return nil
}
}, 0) // This probe is checked once
// Use functions in probes handler
kp := kubeprobes.New(
kp, _ := kubeprobes.New(
kubeprobes.WithLivenessProbes(someOtherProbe),
kubeprobes.WithReadinessProbes(someProbe),
)
```
### Stateful probes
### Manual probes
Stateful probes (objects of type `StatefulProbe`) are objects that can be marked either as "up" (healthy) or "down" (unhealthy) and provide a `ProbeFunction` for easy integration. Those objects utilize `sync.Mutex` mechanism to provide thread-safety.
Manual probes (instances of `ManualProbe` interface) are objects that can be marked either as healthy or unhealthy and implement `Probe` for easy integration. Those objects utilize `sync.RMutex` mechanism to ensure thread-safety.
Those probes can be changed by user with provided methods:
- `Pass()` marks probe as healthy;
- `Fail()` marks probe as unhealthy with generic cause;
- `FailWithCause(someError)` marks probe as unhealthy with given error as cause.
```go
// Unhealthy by default
someProbe := kubeprobes.NewStatefulProbe()
someOtherProbe := kubeprobes.NewStatefulProbe()
someProbe := kubeprobes.NewManualProbe("live")
someOtherProbe := kubeprobes.NewManualProbe("ready")
// Use it in probes handler
kp := kubeprobes.New(
kubeprobes.WithLivenessProbes(someProbe.GetProbeFunction()),
kubeprobes.WithReadinessProbes(someOtherProbe.GetProbeFunction()),
kp, _ := kubeprobes.New(
kubeprobes.WithLivenessProbes(someProbe),
kubeprobes.WithReadinessProbes(someOtherProbe),
)
// Can be later marked according to needs
someProbe.Pass()
someOtherProbe.FailWithCause(errors.New("I'm not doing anything!"))
```
## Direct handler access
It is possible to fetch `http.Handler`s for liveness & readiness probes from `kubeprobes.Kubeprobes` instance as follows:
```go
kp, _ := kubeprobes.New(
// ...
)
livenessHandler := kp.LivenessHandler()
readinessHandler := kp.ReadinessHandler()
```
Those handler can be used for manually mounting them on other servers/routers/muxes (eg. `go-chi/chi`, `gorilla/mux`, `http`'s `ServeMux` etc.).
## Example usage
```go
// Create stateful probes
live := kubeprobes.NewStatefulProbe()
ready := kubeprobes.NewStatefulProbe()
// Create probe functions
appProbe := func() error {
// Some logic for checking app status
return nil
}
// Create manual probes
live := kubeprobes.NewManualProbe("liveness")
ready := kubeprobes.NewManualProbe("readiness")
// Prepare handler
kp := kubeprobes.New(
kubeprobes.WithLivenessProbes(live.GetProbeFunction()),
kubeprobes.WithReadinessProbes(ready.GetProbeFunction()),
kp, err := kubeprobes.New(
kubeprobes.WithLivenessProbes(live),
kubeprobes.WithReadinessProbes(ready, appProbe),
kubeprobes.WithLivenessPath("/livez"),
kubeprobes.WithReadinessPath("/readyz"),
kubeprobes.WithVerboseOutput(),
)
if err != nil {
// Kubeprobes object is validated for invalid or conflicting paths! ;)
panic(err)
}
// Start the probes server
probes := &http.Server{
@ -90,6 +134,6 @@ probes := &http.Server{
go probes.ListenAndServe()
// Mark probes as healthy
live.MarkAsUp()
ready.MarkAsUp()
live.Pass()
ready.Pass()
```

View File

@ -1,44 +0,0 @@
package kubeprobes
import "sync"
// ProbeFunction is a function that determines whether
// the given metric may be marked as correctly functioning.
// It not, the error should be returned.
type ProbeFunction func() error
type statusQuery struct {
allGreen bool
mux sync.Mutex
wg sync.WaitGroup
}
func (sq *statusQuery) isAllGreen() bool {
sq.wg.Wait()
sq.mux.Lock()
defer sq.mux.Unlock()
return sq.allGreen
}
func newStatusQuery(probes []ProbeFunction) *statusQuery {
sq := &statusQuery{
allGreen: true,
mux: sync.Mutex{},
wg: sync.WaitGroup{},
}
sq.wg.Add(len(probes))
for _, probe := range probes {
probe := probe
go func() {
defer sq.wg.Done()
if err := probe(); err != nil {
sq.mux.Lock()
sq.allGreen = false
sq.mux.Unlock()
}
}()
}
return sq
}

View File

@ -1,45 +0,0 @@
package kubeprobes
import (
"errors"
"testing"
"time"
)
func TestStatusQueryIsAllGreen(t *testing.T) {
tests := map[string]struct {
probes []ProbeFunction
expectedStatus bool
}{
"all green": {
probes: []ProbeFunction{
func() error { return nil },
func() error { time.Sleep(2 * time.Second); return nil },
},
expectedStatus: true,
},
"some failed": {
probes: []ProbeFunction{
func() error { return nil },
func() error { time.Sleep(2 * time.Second); return errors.New("failed") },
},
expectedStatus: false,
},
"all failed": {
probes: []ProbeFunction{
func() error { return errors.New("failed") },
func() error { time.Sleep(2 * time.Second); return errors.New("failed") },
},
expectedStatus: false,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
sq := newStatusQuery(test.probes)
if sq.isAllGreen() != test.expectedStatus {
t.Errorf("expected status %v, got %v", test.expectedStatus, sq.isAllGreen())
}
})
}
}

21
costants.go Normal file
View File

@ -0,0 +1,21 @@
package kubeprobes
import (
"errors"
)
const (
defaultLivenessPath string = "/live"
defaultReadinessPath string = "/ready"
verboseOutputFlag string = "v"
)
const (
headerContentType string = "Content-Type"
contentTypeJSON string = "application/json"
)
var (
errProbeNameEmpty error = errors.New("probe name must not be empty")
errProbeFailed error = errors.New("probe marked as failed")
)

147
kubeprobes.go Normal file
View File

@ -0,0 +1,147 @@
package kubeprobes
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
// Kubeprobes represents liveness & readiness probes handler.
type Kubeprobes interface {
http.Handler
// LivenessHandler returns [http.Handler] for liveness probes.
LivenessHandler() http.Handler
// ReadinessHandler returns [http.Handler] for readiness probes.
ReadinessHandler() http.Handler
}
type kubeprobes struct {
livenessProbes []Probe
readinessProbes []Probe
verbose bool
pathLive string
pathReady string
}
// New returns a new instance of a Kubernetes probes with given options.
func New(options ...Option) (Kubeprobes, error) {
kp := &kubeprobes{
livenessProbes: []Probe{},
readinessProbes: []Probe{},
pathLive: defaultLivenessPath,
pathReady: defaultReadinessPath,
}
for _, option := range options {
option.apply(kp)
}
if err := kp.validate(); err != nil {
return nil, err
}
return kp, nil
}
func (kp *kubeprobes) validate() error {
var err error
if kp.pathLive == "" {
err = errors.Join(err, fmt.Errorf("liveness probe path must not be empty"))
}
if kp.pathReady == "" {
err = errors.Join(err, fmt.Errorf("readiness probe path must not be empty"))
}
if !strings.HasPrefix(kp.pathLive, "/") {
err = errors.Join(err, fmt.Errorf("liveness probe path must start with slash (current: %q)", kp.pathLive))
}
if !strings.HasPrefix(kp.pathReady, "/") {
err = errors.Join(err, fmt.Errorf("readiness probe path must start with slash (current: %q)", kp.pathReady))
}
if kp.pathLive == kp.pathReady {
err = errors.Join(err, fmt.Errorf("liveness and readiness probes have the same values (both %q)", kp.pathLive))
}
if len(kp.livenessProbes) == 0 {
err = errors.Join(err, fmt.Errorf("no liveness probes defined"))
}
if len(kp.readinessProbes) == 0 {
err = errors.Join(err, fmt.Errorf("no readiness probes defined"))
}
return err
}
type probesResponse struct {
Passed []statusEntry `json:"passed,omitempty"`
Failed []statusEntry `json:"failed,omitempty"`
}
func (kp *kubeprobes) handleLiveness(w http.ResponseWriter, r *http.Request) {
sq := newStatusQuery(kp.livenessProbes)
output := probesResponse{}
sq.wait()
output.Failed = sq.failed
if r.URL.Query().Has(verboseOutputFlag) || kp.verbose {
output.Passed = sq.passed
}
w.Header().Add(headerContentType, contentTypeJSON)
if sq.ok {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
_ = json.NewEncoder(w).Encode(output)
}
func (kp *kubeprobes) handleReadiness(w http.ResponseWriter, r *http.Request) {
sq := newStatusQuery(append(kp.livenessProbes, kp.readinessProbes...))
output := probesResponse{}
sq.wait()
output.Failed = sq.failed
if r.URL.Query().Has(verboseOutputFlag) || kp.verbose {
output.Passed = sq.passed
}
w.Header().Add(headerContentType, contentTypeJSON)
if sq.ok {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
_ = json.NewEncoder(w).Encode(output)
}
// LivenessHandler implements Kubeprobes.
func (kp *kubeprobes) LivenessHandler() http.Handler {
return http.HandlerFunc(kp.handleLiveness)
}
// ReadinessHandler implements Kubeprobes.
func (kp *kubeprobes) ReadinessHandler() http.Handler {
return http.HandlerFunc(kp.handleReadiness)
}
// ServeHTTP implements Kubeprobes.
func (kp *kubeprobes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case kp.pathLive:
kp.handleLiveness(w, r)
case kp.pathReady:
kp.handleReadiness(w, r)
default:
w.WriteHeader(http.StatusNotFound)
}
}

47
kubeprobes_options.go Normal file
View File

@ -0,0 +1,47 @@
package kubeprobes
// Option represents a [Kubeprobes] constructor option.
type Option interface {
apply(kp *kubeprobes)
}
type option func(*kubeprobes)
func (o option) apply(kp *kubeprobes) {
o(kp)
}
// WithLivenessProbes adds given probe functions to the set of liveness probes.
func WithLivenessProbes(probes ...Probe) Option {
return option(func(kp *kubeprobes) {
kp.livenessProbes = append(kp.livenessProbes, probes...)
})
}
// WithLivenessPath sets custom path for liveness probe (default is "/live").
func WithLivenessPath(path string) Option {
return option(func(kp *kubeprobes) {
kp.pathLive = path
})
}
// WithReadinessProbes adds given probe functions to the set of readiness probes.
func WithReadinessProbes(probes ...Probe) Option {
return option(func(kp *kubeprobes) {
kp.readinessProbes = append(kp.readinessProbes, probes...)
})
}
// WithReadinessPath sets custom path for readiness probe (default is "/ready").
func WithReadinessPath(path string) Option {
return option(func(kp *kubeprobes) {
kp.pathReady = path
})
}
// WithVerboseOutput enables verbose output for every request.
func WithVerboseOutput() Option {
return option(func(kp *kubeprobes) {
kp.verbose = true
})
}

182
kubeprobes_test.go Normal file
View File

@ -0,0 +1,182 @@
package kubeprobes
import (
"net/http"
"net/http/httptest"
"testing"
)
func getStatusFromEndpoint(t *testing.T, client *http.Client, endpoint string) int {
t.Helper()
resp, err := client.Get(endpoint)
if err != nil {
t.Errorf("error getting status from endpoint: %s", err)
}
return resp.StatusCode
}
func TestValidation(t *testing.T) {
var (
live, _ = NewManualProbe("live")
ready, _ = NewManualProbe("ready")
)
tests := map[string]struct {
opts []Option
expectedError bool
}{
"no modifications and no error": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
},
},
"modifications and no error": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
WithLivenessPath("/livez"),
WithReadinessPath("/readyz"),
},
},
"missing liveness probes": {
opts: []Option{
WithReadinessProbes(ready),
},
expectedError: true,
},
"missing readiness probes": {
opts: []Option{
WithLivenessProbes(live),
},
expectedError: true,
},
"liveness probe path empty": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
WithLivenessPath(""),
},
expectedError: true,
},
"readiness probe path empty": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
WithReadinessPath(""),
},
expectedError: true,
},
"liveness probe path does not start with slash": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
WithLivenessPath("livez"),
},
expectedError: true,
},
"readiness probe path does not start with slash": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
WithReadinessPath("readyz"),
},
expectedError: true,
},
"liveness and readiness probe paths are equal": {
opts: []Option{
WithLivenessProbes(live),
WithReadinessProbes(ready),
WithLivenessPath("/check"),
WithReadinessPath("/check"),
},
expectedError: true,
},
}
for name, tc := range tests {
name, tc := name, tc
t.Run(name, func(t *testing.T) {
_, err := New(tc.opts...)
switch {
case err == nil && tc.expectedError:
t.Error("expected error, but no error was returned")
case err != nil && !tc.expectedError:
t.Errorf("expected no error but got %v", err)
}
})
}
}
func TestHandler(t *testing.T) {
var (
live, _ = NewManualProbe("live")
ready, _ = NewManualProbe("ready")
)
tests := map[string]struct {
livenessProbeTransformation func(*testing.T, ManualProbe)
readinessProbeTransformation func(*testing.T, ManualProbe)
expectedLiveStatus int
expectedReadyStatus int
}{
"not live": {
livenessProbeTransformation: markAsDown,
readinessProbeTransformation: markAsDown,
expectedLiveStatus: http.StatusServiceUnavailable,
expectedReadyStatus: http.StatusServiceUnavailable,
},
"live but not ready": {
livenessProbeTransformation: markAsUp,
readinessProbeTransformation: markAsDown,
expectedLiveStatus: http.StatusOK,
expectedReadyStatus: http.StatusServiceUnavailable,
},
"live and ready": {
livenessProbeTransformation: markAsUp,
readinessProbeTransformation: markAsUp,
expectedLiveStatus: http.StatusOK,
expectedReadyStatus: http.StatusOK,
},
"ready but not live - should never happen": {
livenessProbeTransformation: markAsDown,
readinessProbeTransformation: markAsUp,
expectedLiveStatus: http.StatusServiceUnavailable,
expectedReadyStatus: http.StatusServiceUnavailable,
},
}
kp, err := New(
WithLivenessProbes(live),
WithReadinessProbes(ready),
)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
srv := httptest.NewServer(kp)
defer srv.Close()
client := srv.Client()
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
test.livenessProbeTransformation(t, live)
test.readinessProbeTransformation(t, ready)
liveStatus := getStatusFromEndpoint(t, client, srv.URL+defaultLivenessPath)
readyStatus := getStatusFromEndpoint(t, client, srv.URL+defaultReadinessPath)
otherStatus := getStatusFromEndpoint(t, client, srv.URL+"/something")
if liveStatus != test.expectedLiveStatus {
t.Errorf("expected live status %d, got %d", test.expectedLiveStatus, liveStatus)
}
if readyStatus != test.expectedReadyStatus {
t.Errorf("expected ready status %d, got %d", test.expectedReadyStatus, readyStatus)
}
if otherStatus != http.StatusNotFound {
t.Errorf("expected 404 status, got %d", otherStatus)
}
})
}
}

3379
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,18 @@
{
"private": true,
"name": "kubeprobes",
"version": "1.1.0-rc.1",
"version": "1.3.2-rc.3",
"scripts": {
"release": "./node_modules/.bin/semantic-release"
},
"devDependencies": {
"@saithodev/semantic-release-gitea": "^2.1.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^11.0.0",
"@semantic-release/commit-analyzer": "^13.0.0",
"@semantic-release/git": "^10.0.1",
"@semantic-release/npm": "^11.0.1",
"@semantic-release/release-notes-generator": "^12.0.1",
"conventional-changelog-conventionalcommits": "^7.0.2",
"semantic-release": "^23.0.0"
"@semantic-release/npm": "^12.0.0",
"@semantic-release/release-notes-generator": "^14.0.0",
"conventional-changelog-conventionalcommits": "^8.0.0",
"semantic-release": "^24.0.0"
}
}

81
probe.go Normal file
View File

@ -0,0 +1,81 @@
package kubeprobes
import (
"sync"
"time"
)
// Probe is a wrapper for a function that determines whether
// the given metric may be marked as correctly functioning.
// It not, the error should be returned.
type Probe interface {
name() string
status() error
}
type probe struct {
probeName string
probeFunc func() error
refreshInterval time.Duration
mux sync.RWMutex
err error
}
// NewProbe returns new instance of [Probe].
//
// If update interval is less or equal zero then probe is updated only
// on its creation and remains in the same state forever.
func NewProbe(
name string,
fn func() error,
updateInterval time.Duration,
) (Probe, error) {
if name == "" {
return nil, errProbeNameEmpty
}
pf := &probe{
probeName: name,
probeFunc: fn,
refreshInterval: updateInterval,
mux: sync.RWMutex{},
}
defer pf.autoUpdate()
return pf, nil
}
// name implements ProbeFunction.
func (pf *probe) name() string {
return pf.probeName
}
// status implements ProbeFunction.
func (pf *probe) status() error {
pf.mux.RLock()
defer pf.mux.RUnlock()
return pf.err
}
func (pf *probe) update() {
err := pf.probeFunc()
pf.mux.Lock()
pf.err = err
pf.mux.Unlock()
}
func (pf *probe) autoUpdate() {
pf.update()
if pf.refreshInterval <= 0 {
return
}
go func() {
ticker := time.NewTicker(pf.refreshInterval)
for {
<-ticker.C
pf.update()
}
}()
}

71
probe_manual.go Normal file
View File

@ -0,0 +1,71 @@
package kubeprobes
import (
"sync"
)
// ManualProbe represents the simple probe that can be either
// marked as "up" (healthy) or "down" (unhealthy).
type ManualProbe interface {
Probe
// Pass marks the probe as healthy.
Pass()
// Fail marks the probe as unhealthy.
Fail()
// FailWitCause marks the probe as unhealthy with given cause.
FailWithCause(err error)
}
type manualProbe struct {
probeName string
err error
mux sync.RWMutex
}
// NewManualProbe returns a new instance of a manual probe
// which can be either marked as healthy or unhealthy.
// The probe is initially marked as unhealthy.
func NewManualProbe(name string) (ManualProbe, error) {
if name == "" {
return nil, errProbeNameEmpty
}
return &manualProbe{
probeName: name,
mux: sync.RWMutex{},
}, nil
}
// name implements ManualProbe.
func (mp *manualProbe) name() string {
return mp.probeName
}
// status implements ManualProbe.
func (mp *manualProbe) status() error {
mp.mux.RLock()
defer mp.mux.RUnlock()
return mp.err
}
// Pass implements ManualProbe.
func (mp *manualProbe) Pass() {
mp.mux.Lock()
defer mp.mux.Unlock()
mp.err = nil
}
// Fail implements ManualProbe.
func (mp *manualProbe) Fail() {
mp.mux.Lock()
defer mp.mux.Unlock()
mp.err = errProbeFailed
}
// FailWithCause implements ManualProbe.
func (mp *manualProbe) FailWithCause(err error) {
mp.mux.Lock()
defer mp.mux.Unlock()
mp.err = err
}

46
probe_manual_test.go Normal file
View File

@ -0,0 +1,46 @@
package kubeprobes
import "testing"
var (
markAsDown func(*testing.T, ManualProbe) = func(t *testing.T, sp ManualProbe) {
t.Helper()
sp.Fail()
}
markAsUp func(*testing.T, ManualProbe) = func(t *testing.T, sp ManualProbe) {
t.Helper()
sp.Pass()
}
)
func TestManualProbe(t *testing.T) {
tests := map[string]struct {
probeTransformation func(*testing.T, ManualProbe)
expectedError bool
}{
"mark as up": {
probeTransformation: markAsUp,
expectedError: false,
},
"mark as down": {
probeTransformation: markAsDown,
expectedError: true,
},
}
for name, tc := range tests {
name, tc := name, tc
t.Run(name, func(t *testing.T) {
sp, _ := NewManualProbe("some name")
tc.probeTransformation(t, sp)
err := sp.status()
switch {
case err == nil && tc.expectedError:
t.Error("expected error, but no error was returned")
case err != nil && !tc.expectedError:
t.Errorf("expected no error but got %v", err)
}
})
}
}

View File

@ -1,64 +0,0 @@
package kubeprobes
import (
"net/http"
"strings"
)
type kubeprobes struct {
livenessProbes []ProbeFunction
readinessProbes []ProbeFunction
}
// ServeHTTP implements http.Handler interface
func (kp *kubeprobes) ServeHTTP(w http.ResponseWriter, r *http.Request) {
subs := strings.Split(strings.TrimSuffix(r.URL.Path, "/"), "/")
switch subs[len(subs)-1] {
case "live":
sq := newStatusQuery(kp.livenessProbes)
if sq.isAllGreen() {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
case "ready":
sq := newStatusQuery(append(kp.livenessProbes, kp.readinessProbes...))
if sq.isAllGreen() {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
default:
w.WriteHeader(http.StatusNotFound)
}
}
type option func(*kubeprobes)
// New returns a new instance of a Kubernetes probes
func New(options ...option) *kubeprobes {
kp := &kubeprobes{
livenessProbes: []ProbeFunction{},
readinessProbes: []ProbeFunction{},
}
for _, option := range options {
option(kp)
}
return kp
}
// WithLivenessProbes adds given liveness probes to the set of probes
func WithLivenessProbes(probes ...ProbeFunction) option {
return func(kp *kubeprobes) {
kp.livenessProbes = append(kp.livenessProbes, probes...)
}
}
// WithReadinessProbes adds given readiness probes to the set of probes
func WithReadinessProbes(probes ...ProbeFunction) option {
return func(kp *kubeprobes) {
kp.readinessProbes = append(kp.readinessProbes, probes...)
}
}

View File

@ -1,83 +0,0 @@
package kubeprobes
import (
"net/http"
"net/http/httptest"
"testing"
)
func getStatusFromEndpoint(t *testing.T, client *http.Client, endpoint string) int {
t.Helper()
resp, err := client.Get(endpoint)
if err != nil {
t.Errorf("error getting status from endpoint: %s", err)
}
return resp.StatusCode
}
func TestKubeprobes(t *testing.T) {
live, ready := NewStatefulProbe(), NewStatefulProbe()
tests := map[string]struct {
livenessProbeTransformation func(*testing.T, *StatefulProbe)
readinessProbeTransformation func(*testing.T, *StatefulProbe)
expectedLiveStatus int
expectedReadyStatus int
}{
"not live": {
livenessProbeTransformation: markAsDown,
readinessProbeTransformation: markAsDown,
expectedLiveStatus: http.StatusServiceUnavailable,
expectedReadyStatus: http.StatusServiceUnavailable,
},
"live but not ready": {
livenessProbeTransformation: markAsUp,
readinessProbeTransformation: markAsDown,
expectedLiveStatus: http.StatusOK,
expectedReadyStatus: http.StatusServiceUnavailable,
},
"live and ready": {
livenessProbeTransformation: markAsUp,
readinessProbeTransformation: markAsUp,
expectedLiveStatus: http.StatusOK,
expectedReadyStatus: http.StatusOK,
},
"ready but not live - should never happen": {
livenessProbeTransformation: markAsDown,
readinessProbeTransformation: markAsUp,
expectedLiveStatus: http.StatusServiceUnavailable,
expectedReadyStatus: http.StatusServiceUnavailable,
},
}
kp := New(
WithLivenessProbes(live.GetProbeFunction()),
WithReadinessProbes(ready.GetProbeFunction()),
)
srv := httptest.NewServer(kp)
defer srv.Close()
client := srv.Client()
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
test.livenessProbeTransformation(t, live)
test.readinessProbeTransformation(t, ready)
liveStatus := getStatusFromEndpoint(t, client, srv.URL+"/live")
readyStatus := getStatusFromEndpoint(t, client, srv.URL+"/ready")
otherStatus := getStatusFromEndpoint(t, client, srv.URL+"/something")
if liveStatus != test.expectedLiveStatus {
t.Errorf("expected live status %d, got %d", test.expectedLiveStatus, liveStatus)
}
if readyStatus != test.expectedReadyStatus {
t.Errorf("expected ready status %d, got %d", test.expectedReadyStatus, readyStatus)
}
if otherStatus != http.StatusNotFound {
t.Errorf("expected 404 status, got %d", otherStatus)
}
})
}
}

54
query.go Normal file
View File

@ -0,0 +1,54 @@
package kubeprobes
import "sync"
type statusQuery struct {
ok bool
passed []statusEntry
failed []statusEntry
mux sync.Mutex
wg sync.WaitGroup
}
type statusEntry struct {
Probe string `json:"probe"`
Status error `json:"status,omitempty"`
}
func (sq *statusQuery) wait() {
sq.wg.Wait()
}
func newStatusQuery(probes []Probe) *statusQuery {
sq := &statusQuery{
ok: true,
passed: make([]statusEntry, 0, len(probes)),
failed: make([]statusEntry, 0, len(probes)),
mux: sync.Mutex{},
wg: sync.WaitGroup{},
}
sq.wg.Add(len(probes))
for _, probe := range probes {
probe := probe
go func() {
defer sq.wg.Done()
sq.mux.Lock()
if err := probe.status(); err != nil {
sq.ok = false
sq.failed = append(sq.failed, statusEntry{
Probe: probe.name(),
Status: err,
})
} else {
sq.passed = append(sq.passed, statusEntry{
Probe: probe.name(),
})
}
sq.mux.Unlock()
}()
}
return sq
}

44
query_test.go Normal file
View File

@ -0,0 +1,44 @@
package kubeprobes
import (
"testing"
)
func TestStatusQueryIsAllGreen(t *testing.T) {
var (
probePassing, _ = NewProbe("pass", func() error {
return nil
}, 0)
probeFailing, _ = NewProbe("fail", func() error {
return errProbeFailed
}, 0)
)
tests := map[string]struct {
probes []Probe
expectedStatus bool
}{
"all green": {
probes: []Probe{probePassing},
expectedStatus: true,
},
"some failed": {
probes: []Probe{probePassing, probeFailing},
expectedStatus: false,
},
"all failed": {
probes: []Probe{probeFailing},
expectedStatus: false,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
sq := newStatusQuery(test.probes)
sq.wait()
if sq.ok != test.expectedStatus {
t.Errorf("expected status %v, got %v", test.expectedStatus, sq.ok)
}
})
}
}

View File

@ -1,52 +0,0 @@
package kubeprobes
import (
"errors"
"sync"
)
var errProbeDown = errors.New("DOWN")
// StatefulProbe represents the simple probe that can be either
// marked as "up" (healthy) or "down" (unhealthy).
type StatefulProbe struct {
status bool
mux sync.Mutex
}
// NewStatefulProbe returns a new instance of a stateful probe
// which can be either marked as "up" (healthy) or "down" (unhealthy).
// The probe is initially marked as "down".
func NewStatefulProbe() *StatefulProbe {
return &StatefulProbe{
status: false,
mux: sync.Mutex{},
}
}
// MarkAsUp marks the probe as healthy
func (sp *StatefulProbe) MarkAsUp() {
sp.mux.Lock()
defer sp.mux.Unlock()
sp.status = true
}
// MarkAsDown marks the probe as unhealthy
func (sp *StatefulProbe) MarkAsDown() {
sp.mux.Lock()
defer sp.mux.Unlock()
sp.status = false
}
// GetProbeFunction returns a function that can be used to check
// whether the probe is healthy or not.
func (sp *StatefulProbe) GetProbeFunction() ProbeFunction {
return func() error {
sp.mux.Lock()
defer sp.mux.Unlock()
if sp.status {
return nil
}
return errProbeDown
}
}

View File

@ -1,42 +0,0 @@
package kubeprobes
import "testing"
var (
markAsDown func(*testing.T, *StatefulProbe) = func(t *testing.T, sp *StatefulProbe) {
t.Helper()
sp.MarkAsDown()
}
markAsUp func(*testing.T, *StatefulProbe) = func(t *testing.T, sp *StatefulProbe) {
t.Helper()
sp.MarkAsUp()
}
)
func TestStatefulProbe(t *testing.T) {
tests := map[string]struct {
probeTransformation func(*testing.T, *StatefulProbe)
expectedError bool
}{
"mark as up": {
probeTransformation: markAsUp,
expectedError: false,
},
"mark as down": {
probeTransformation: markAsDown,
expectedError: true,
},
}
for name, test := range tests {
name, test := name, test
t.Run(name, func(t *testing.T) {
sp := NewStatefulProbe()
test.probeTransformation(t, sp)
probeFunc := sp.GetProbeFunction()
if (probeFunc() != nil) != test.expectedError {
t.Error("result not as expected")
}
})
}
}