Compare commits

..

No commits in common. "e830e255608756591897fae7ba658170a02e28a3" and "24cb5d816a353aee3968da44b1392031d5b554b2" have entirely different histories.

12 changed files with 1328 additions and 2297 deletions

View File

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

View File

@ -1,86 +1,3 @@
## [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) ## [1.3.0](https://git.ext.icikowski.pl/go/kubeprobes/compare/v1.2.0...v1.3.0) (2024-03-02)

View File

@ -1,7 +1,5 @@
# kubeprobes # 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. 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 ## Installation
@ -23,22 +21,22 @@ Default paths can be overriden with options described below. Accessing any other
The `kubeprobes.New` function accepts following options as arguments: The `kubeprobes.New` function accepts following options as arguments:
- `kubeprobes.WithLivenessProbes(...)` - adds particular [probes](#probes) to the list of liveness probes; - `kubeprobes.WithLivenessProbes(...)` - adds particular [probe functions](#probe-functions) to the list of liveness probes;
- `kubeprobes.WithLivenessPath("/some/liveness/path")` - sets liveness probe path to given path (default is `/live`); - `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.WithReadinessProbes(...)` - adds particular [probe functions](#probe-functions) to the list of readiness probes;
- `kubeprobes.WithReadinessPath("/some/readiness/path")` - sets readiness probe path to given path (default is `/ready`); - `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). - `kubeprobes.WithVerboseOutput()` - enables verbose output by default (returns both failed and passed probes).
## Probes ## 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). 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 [manual probes](#manual-probes).
### Standard probes ### Probe functions
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. Probe functions (instances of `ProbeFunction` 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 ```go
someProbe := kubeprobes.NewProbe("live", func() error { someProbe := kubeprobes.NewProbeFunction("live", func() error {
// Some logic here // Some logic here
if time.Now().Weekday() == time.Wednesday { if time.Now().Weekday() == time.Wednesday {
// Fail only on wednesday! // Fail only on wednesday!
@ -47,7 +45,7 @@ someProbe := kubeprobes.NewProbe("live", func() error {
return nil return nil
}, 1 * time.Hour) }, 1 * time.Hour)
someOtherProbe := kubeprobes.NewProbe("ready", func() error { someOtherProbe := kubeprobes.NewProbeFunction("ready", func() error {
// Always healthy // Always healthy
return nil return nil
}, 0) // This probe is checked once }, 0) // This probe is checked once
@ -61,7 +59,7 @@ kp, _ := kubeprobes.New(
### Manual probes ### Manual probes
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. Manual probes (instances of `ManualProbe` interface) are objects that can be marked either as healthy or unhealthy and implement `ProbeFunction` for easy integration. Those objects utilize `sync.RMutex` mechanism to ensure thread-safety.
Those probes can be changed by user with provided methods: Those probes can be changed by user with provided methods:
@ -80,9 +78,7 @@ kp, _ := kubeprobes.New(
kubeprobes.WithReadinessProbes(someOtherProbe), kubeprobes.WithReadinessProbes(someOtherProbe),
) )
// Can be later marked according to needs // Can be later marked according
someProbe.Pass()
someOtherProbe.FailWithCause(errors.New("I'm not doing anything!"))
``` ```
## Direct handler access ## Direct handler access
@ -109,9 +105,9 @@ appProbe := func() error {
return nil return nil
} }
// Create manual probes // Create stateful probes
live := kubeprobes.NewManualProbe("liveness") live := kubeprobes.NewStatefulProbe()
ready := kubeprobes.NewManualProbe("readiness") ready := kubeprobes.NewStatefulProbe()
// Prepare handler // Prepare handler
kp, err := kubeprobes.New( kp, err := kubeprobes.New(

View File

@ -19,8 +19,8 @@ type Kubeprobes interface {
} }
type kubeprobes struct { type kubeprobes struct {
livenessProbes []Probe livenessProbes []ProbeFunction
readinessProbes []Probe readinessProbes []ProbeFunction
verbose bool verbose bool
@ -31,8 +31,8 @@ type kubeprobes struct {
// New returns a new instance of a Kubernetes probes with given options. // New returns a new instance of a Kubernetes probes with given options.
func New(options ...Option) (Kubeprobes, error) { func New(options ...Option) (Kubeprobes, error) {
kp := &kubeprobes{ kp := &kubeprobes{
livenessProbes: []Probe{}, livenessProbes: []ProbeFunction{},
readinessProbes: []Probe{}, readinessProbes: []ProbeFunction{},
pathLive: defaultLivenessPath, pathLive: defaultLivenessPath,
pathReady: defaultReadinessPath, pathReady: defaultReadinessPath,
} }

View File

@ -12,7 +12,7 @@ func (o option) apply(kp *kubeprobes) {
} }
// WithLivenessProbes adds given probe functions to the set of liveness probes. // WithLivenessProbes adds given probe functions to the set of liveness probes.
func WithLivenessProbes(probes ...Probe) Option { func WithLivenessProbes(probes ...ProbeFunction) Option {
return option(func(kp *kubeprobes) { return option(func(kp *kubeprobes) {
kp.livenessProbes = append(kp.livenessProbes, probes...) kp.livenessProbes = append(kp.livenessProbes, probes...)
}) })
@ -26,7 +26,7 @@ func WithLivenessPath(path string) Option {
} }
// WithReadinessProbes adds given probe functions to the set of readiness probes. // WithReadinessProbes adds given probe functions to the set of readiness probes.
func WithReadinessProbes(probes ...Probe) Option { func WithReadinessProbes(probes ...ProbeFunction) Option {
return option(func(kp *kubeprobes) { return option(func(kp *kubeprobes) {
kp.readinessProbes = append(kp.readinessProbes, probes...) kp.readinessProbes = append(kp.readinessProbes, probes...)
}) })

2805
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -7,7 +7,7 @@ import (
// ManualProbe represents the simple probe that can be either // ManualProbe represents the simple probe that can be either
// marked as "up" (healthy) or "down" (unhealthy). // marked as "up" (healthy) or "down" (unhealthy).
type ManualProbe interface { type ManualProbe interface {
Probe ProbeFunction
// Pass marks the probe as healthy. // Pass marks the probe as healthy.
Pass() Pass()

View File

@ -20,7 +20,7 @@ func (sq *statusQuery) wait() {
sq.wg.Wait() sq.wg.Wait()
} }
func newStatusQuery(probes []Probe) *statusQuery { func newStatusQuery(probes []ProbeFunction) *statusQuery {
sq := &statusQuery{ sq := &statusQuery{
ok: true, ok: true,
passed: make([]statusEntry, 0, len(probes)), passed: make([]statusEntry, 0, len(probes)),

View File

@ -6,28 +6,28 @@ import (
func TestStatusQueryIsAllGreen(t *testing.T) { func TestStatusQueryIsAllGreen(t *testing.T) {
var ( var (
probePassing, _ = NewProbe("pass", func() error { probePassing, _ = NewProbeFunction("pass", func() error {
return nil return nil
}, 0) }, 0)
probeFailing, _ = NewProbe("fail", func() error { probeFailing, _ = NewProbeFunction("fail", func() error {
return errProbeFailed return errProbeFailed
}, 0) }, 0)
) )
tests := map[string]struct { tests := map[string]struct {
probes []Probe probes []ProbeFunction
expectedStatus bool expectedStatus bool
}{ }{
"all green": { "all green": {
probes: []Probe{probePassing}, probes: []ProbeFunction{probePassing},
expectedStatus: true, expectedStatus: true,
}, },
"some failed": { "some failed": {
probes: []Probe{probePassing, probeFailing}, probes: []ProbeFunction{probePassing, probeFailing},
expectedStatus: false, expectedStatus: false,
}, },
"all failed": { "all failed": {
probes: []Probe{probeFailing}, probes: []ProbeFunction{probeFailing},
expectedStatus: false, expectedStatus: false,
}, },
} }