diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c7c8504..28ca10d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -34,18 +34,18 @@ jobs:
if: needs.semantic-release.outputs.new-release-published == 'true'
strategy:
matrix:
- repos: ['mission-control', 'canary-checker', 'commons', 'config-db', 'gomplate']
+ repos: ["mission-control", "canary-checker", "commons", "config-db", "gomplate"]
steps:
- uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
with:
repository: flanksource/${{ matrix.repos }}
token: ${{ secrets.FLANKBOT }}
-
+
- name: Setup Go
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: v1.22.x
-
+
- name: Create commits
run: |
# Sleep to let index refresh
@@ -60,9 +60,9 @@ jobs:
id: cpr
uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5
with:
- branch: 'bump-is-healthy-auto-pr'
- commit-message: 'chore: bump is-healthy to v${{ needs.semantic-release.outputs.release-version }}'
- title: 'chore: bump is-healthy to v${{ needs.semantic-release.outputs.release-version }}'
+ branch: "bump-is-healthy-auto-pr"
+ commit-message: "chore: bump is-healthy to v${{ needs.semantic-release.outputs.release-version }}"
+ title: "chore: bump is-healthy to v${{ needs.semantic-release.outputs.release-version }}"
token: ${{ secrets.FLANKBOT }}
labels: dependencies
@@ -74,3 +74,23 @@ jobs:
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
merge-method: squash
repository: flanksource/${{ matrix.repos }}
+ goreleaser:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: stable
+
+ - name: Run GoReleaser
+ uses: goreleaser/goreleaser-action@v6
+ with:
+ distribution: goreleaser
+ version: "~> v2"
+ args: release --clean
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 3b735ec..4092658 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,5 @@
# Go workspace file
go.work
+# Added by goreleaser init:
+dist/
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
new file mode 100644
index 0000000..e1777de
--- /dev/null
+++ b/.goreleaser.yaml
@@ -0,0 +1,26 @@
+version: 2
+
+before:
+ hooks:
+ - go mod tidy
+
+builds:
+ - env:
+ - CGO_ENABLED=0
+ goos:
+ - linux
+ - windows
+ - darwin
+ goarch:
+ - amd64
+ - arm64
+
+changelog:
+ sort: asc
+ filters:
+ exclude:
+ - "^docs:"
+ - "^test:"
+
+release:
+ footer: >-
diff --git a/Makefile b/Makefile
index 42b1c21..57b30a9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,32 @@
+
+NAME=is-healthy
+YQ=yq
+OS ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
+ARCH ?= $(shell uname -m | sed 's/x86_64/amd64/')
+LD_FLAGS=-ldflags "-w -s -X \"main.version=$(VERSION_TAG)\""
+ifeq ($(VERSION),)
+ VERSION_TAG=$(shell git describe --abbrev=0 --tags || echo latest)
+else
+ VERSION_TAG=$(VERSION)
+endif
+
+
+# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
+ifeq (,$(shell go env GOBIN))
+GOBIN=$(shell go env GOPATH)/bin
+else
+GOBIN=$(shell go env GOBIN)
+endif
+
.PHONY: test
test:
go test ./... -v
-.PHONY: tidy
-tidy:
- go mod tidy -go=1.20 -compat=1.20
.PHONY: lint
-lint:
+lint: fmt
golangci-lint run
-
- golines -m 120 -w pkg/
- golines -m 120 -w events/
- gofumpt -w .
.PHONY:
sync:
@@ -21,3 +34,48 @@ sync:
update-submodules:
git submodule update --remote --merge && git submodule sync
+
+
+tidy:
+ go mod tidy
+
+fmt:
+ golines -m 120 -w pkg/
+ golines -m 120 -w events/
+ gofumpt -w .
+
+.PHONY: compress
+compress:
+ test -e ./$(RELEASE_DIR)/$(NAME)_linux_amd64 && upx -5 ./$(RELEASE_DIR)/$(NAME)_linux_amd64 || true
+ test -e ./$(RELEASE_DIR)/$(NAME)_linux_arm64 && upx -5 ./$(RELEASE_DIR)/$(NAME)_linux_arm64 || true
+
+.PHONY: compress-build
+compress-build:
+ upx -5 ./$(RELEASE_DIR)/$(NAME) ./$(RELEASE_DIR)/$(NAME).test
+
+.PHONY: linux
+linux:
+ GOOS=linux GOARCH=amd64 go build -o ./$(RELEASE_DIR)/$(NAME)_linux_amd64 $(LD_FLAGS) main.go
+ GOOS=linux GOARCH=arm64 go build -o ./$(RELEASE_DIR)/$(NAME)_linux_arm64 $(LD_FLAGS) main.go
+
+.PHONY: darwin
+darwin:
+ GOOS=darwin GOARCH=amd64 go build -o ./$(RELEASE_DIR)/$(NAME)_darwin_amd64 $(LD_FLAGS) main.go
+ GOOS=darwin GOARCH=arm64 go build -o ./$(RELEASE_DIR)/$(NAME)_darwin_arm64 $(LD_FLAGS) main.go
+
+.PHONY: windows
+windows:
+ GOOS=windows GOARCH=amd64 go build -o ./$(RELEASE_DIR)/$(NAME).exe $(LD_FLAGS) main.go
+
+.PHONY: binaries
+binaries: linux darwin windows compress
+
+
+.PHONY: build
+build:
+ GOOS=$(OS) GOARCH=$(ARCH) go build -o ./.bin/$(NAME) $(LD_FLAGS) main.go
+
+
+.PHONY: install
+install:
+ cp ./.bin/$(NAME) /usr/local/bin/
diff --git a/README.md b/README.md
index 8d15faa..fc723f5 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,62 @@
-# is-healthy
+
+`is-healthy` is a heuristic library for checking the health of Kubernetes and Cloud resources, it supports basic, enhanced and heuristic mode.
-`is-healthy` is a library and CLI to test the status of Kubernetes JSON objects, it is copied mostly from the Argocd project and modified to reduce the dependency tree
+
+* **Basic Mode**: Wraps Argo health check functionality. Does not distinguish between `health` and `status`, `lastUpdated` and `ready` are not supported
+ * **health**: One of `healthy`, `unhealthy`, `warning`, `unknown`
+ * **message**: A reason for the status e.g. `Back-off pulling image "nginx:invalid"`
+* **Enhanced Mode**: returns the following fields:
+
+ * ***ready***: Whether the resource is currently being reconciled / provisioned.
+ > `ready` is independent of `health`, e.g. A pod in a failure state can be ready if its state is terminal and will not change.
+ * **health**: One of `healthy`, `unhealthy`, `warning`, `unknown`,
+ > `health` can transition based on the age or last event time of a resource.
+ * **status**: A text description of the state of of resource e.g. `Running` or `ImagePullBackoff`
+ * **message**: A reason for the status e.g. `Back-off pulling image "nginx:invalid"`
+ * **lastUpdated**: The last time the resource was updated
+* **Heuristic Mode**: Attempts to determine health using and fields named `state`, `status` etc..
+
+|Object Type|Support Mode||
+|---|---|---|
+|Core Kubernetes Resources|Enhanced||
+|Pod|Enhanced|Ignores pod restarts for the first `15m`
`warning` if restarted in in last 24h
`unhealthy` if restarted in last `1h`|
+|Certificate|Enhanced|`unhealthy` if not issued with `1h`
`warning` if not issued with `15m`
`warning` if certificate expiry `< 2d`|
+|CronJob|Enhanced||
+|Flux CRD's|Enhanced||
+|Argo CRD's|Enhanced||
+|Cert-Manager CRD's|Enhanced|Marks|
+|Kubernetes Resources using [Conditions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties)|Heuristic||
+
+
+
+
+## Example
+
+```shell
+kubectl po -o json | is-healthy -j
+```
+
+Output:
+
+```json
+{
+ "ready": false,
+ "health": "unhealthy",
+ "status": "ImagePullBackOff",
+ "message": "Back-off pulling image \"nginx:invalid\"",
+ "lastUpdated": "2025-03-26T10:17:18Z"
+}
+```
+
+
+## Attribution
+
+This project builds upon the health check implementations from:
+* [Argo CD](https://github.com/argoproj/argo-cd)
+* [gitops-engine](https://github.com/argoproj/gitops-engine)
diff --git a/go.mod b/go.mod
index a0531a8..fba7810 100644
--- a/go.mod
+++ b/go.mod
@@ -23,10 +23,13 @@ require (
github.com/go-logr/logr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/spf13/cobra v1.9.1 // indirect
+ github.com/spf13/pflag v1.0.6 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/text v0.16.0 // indirect
diff --git a/go.sum b/go.sum
index 3befd97..8dfdf99 100644
--- a/go.sum
+++ b/go.sum
@@ -115,6 +115,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
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/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -308,6 +309,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
@@ -463,6 +466,8 @@ github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJ
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -470,6 +475,8 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
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/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
diff --git a/main.go b/main.go
index 978f9b2..96c8a37 100644
--- a/main.go
+++ b/main.go
@@ -1,39 +1,105 @@
package main
import (
+ "encoding/json"
"fmt"
"io"
"os"
+ "strings"
"github.com/flanksource/is-healthy/pkg/health"
"github.com/flanksource/is-healthy/pkg/lua"
+ "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
)
+var (
+ version = "dev"
+ commit = "none"
+ date = "unknown"
+)
+
+var jsonOut bool
+
func main() {
- stdin, err := io.ReadAll(os.Stdin)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
+ if len(commit) > 8 {
+ version = fmt.Sprintf("%v, commit %v, built at %v", version, commit[0:8], date)
}
- obj := make(map[string]interface{})
- err = yaml.Unmarshal([]byte(stdin), &obj)
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
+ root := &cobra.Command{
+ Use: "is-healthy",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ stdin, err := io.ReadAll(os.Stdin)
+ if err != nil {
+ return err
+ }
+
+ obj := make(map[string]interface{})
+ err = yaml.Unmarshal([]byte(stdin), &obj)
+ if err != nil {
+ return err
+ }
- _health, err := health.GetResourceHealth(&unstructured.Unstructured{Object: obj}, lua.ResourceHealthOverrides{})
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
+ _health, err := health.GetResourceHealth(&unstructured.Unstructured{Object: obj}, lua.ResourceHealthOverrides{})
+ if err != nil {
+ return err
+ }
+
+ if jsonOut {
+ data, _ := json.MarshalIndent(_health, "", " ")
+ fmt.Println(string(data))
+ } else {
+ fmt.Printf("%s\n", *_health)
+ }
+
+ if _health.Health.IsWorseThan(health.HealthUnhealthy) {
+ os.Exit(1)
+ }
+ if _health.Health.IsWorseThan(health.HealthWarning) {
+ os.Exit(2)
+ }
+ return nil
+ },
}
- fmt.Printf("%s\n", *_health)
+ root.AddCommand(&cobra.Command{
+ Use: "version",
+ Short: "Print the version number of is-healthy",
+ Args: cobra.MinimumNArgs(0),
+ Run: func(cmd *cobra.Command, args []string) {
+ fmt.Println(version)
+ },
+ })
+
+ root.AddCommand(&cobra.Command{
+ Use: "supported-types",
+ Short: "Print a list of supported object types",
+ Args: cobra.MinimumNArgs(0),
+ Run: func(cmd *cobra.Command, args []string) {
+ for _, t := range lua.ListResourceTypes() {
+ fmt.Println(t)
+ }
+ for _, t := range health.ListResourceTypes() {
+ if strings.Contains(t, "/") {
+ fmt.Println(t)
+ } else {
+ fmt.Println(t + "/*")
+ }
+ }
+ },
+ })
+
+ root.SetUsageTemplate(root.UsageTemplate() + fmt.Sprintf("\nversion: %s\n ", version))
- if _health.Health.IsWorseThan(health.HealthWarning) {
- os.Exit(1)
+ root.Flags().BoolVarP(&jsonOut, "json", "j", false, "Output in json format")
+ if err := root.Execute(); err != nil {
+ if jsonOut {
+ data, _ := json.MarshalIndent(map[string]interface{}{"error": err.Error()}, "", " ")
+ fmt.Println(string(data))
+ } else {
+ fmt.Println(err)
+ }
+ os.Exit(3)
}
}
diff --git a/pkg/health/health.go b/pkg/health/health.go
index 7c4326e..e0cc658 100644
--- a/pkg/health/health.go
+++ b/pkg/health/health.go
@@ -106,6 +106,7 @@ const (
HealthStatusRestart HealthStatusCode = "Restarting"
HealthStatusStarting HealthStatusCode = "Starting"
HealthStatusFailed HealthStatusCode = "Failed"
+ HealthStatusFailedCreate HealthStatusCode = "Failed Create"
HealthStatusUnschedulable HealthStatusCode = "Unschedulable"
HealthStatusUpgradeFailed HealthStatusCode = "UpgradeFailed"
HealthStatusOOMKilled HealthStatusCode = "OOMKilled"
diff --git a/pkg/health/health_deployment.go b/pkg/health/health_deployment.go
index 69cae8f..7e12658 100644
--- a/pkg/health/health_deployment.go
+++ b/pkg/health/health_deployment.go
@@ -53,13 +53,28 @@ func getReplicaHealth(s ReplicaStatus) *HealthStatus {
age := time.Since(s.Object.GetCreationTimestamp().Time).Truncate(time.Minute).Abs()
gs := GetGenericStatus(s.Object)
+ available := gs.FindCondition("Available")
+ isAvailable := s.Ready > 0
+ if available.Status != "" {
+ isAvailable = available.Status == "True"
+ }
progressing := gs.FindCondition("Progressing")
+
+ failure := gs.FindCondition("ReplicaFailure")
+ if failure.Status == "True" {
+ hs.Status = HealthStatusFailedCreate
+ hs.Health = HealthUnhealthy
+ hs.Message = failure.Message
+ hs.Ready = true
+ return hs
+ }
+
isStarting := age < startDeadline
isProgressDeadlineExceeded := !isStarting && (progressing.Reason == "ProgressDeadlineExceeded")
- hs.Ready = progressing.Status == "True"
+ hs.Ready = progressing.Status == "True" && progressing.Reason != "ReplicaSetUpdated"
- hs.Health = lo.Ternary(s.Ready >= s.Desired, HealthHealthy, lo.Ternary(s.Ready > 0, HealthWarning, HealthUnhealthy))
+ hs.Health = lo.Ternary(isAvailable, HealthHealthy, lo.Ternary(s.Ready > 0, HealthWarning, HealthUnhealthy))
if s.Desired == 0 && s.Replicas == 0 {
hs.Ready = true
@@ -75,26 +90,32 @@ func getReplicaHealth(s ReplicaStatus) *HealthStatus {
hs.Status = "Pending"
hs.Health = HealthUnknown
}
- } else if s.Ready == 0 && isStarting && !isProgressDeadlineExceeded {
- hs.Health = HealthUnknown
+ } else if s.Ready == 0 && isStarting {
hs.Status = HealthStatusStarting
- } else if s.Ready == 0 && !isStarting {
- hs.Health = HealthUnhealthy
- hs.Status = HealthStatusCrashLoopBackoff
+ } else if s.Ready == 0 {
+ hs.Status = lo.Ternary(isAvailable, HealthStatusUpdating, HealthStatusCrashLoopBackoff)
+ }
+
+ if isProgressDeadlineExceeded {
+ hs.Status = HealthStatusRolloutFailed
+ hs.Health = hs.Health.Worst(HealthWarning)
} else if s.Desired == 0 && s.Replicas > 0 {
hs.Status = HealthStatusScalingDown
- hs.Health = lo.Ternary(isProgressDeadlineExceeded, HealthWarning, HealthHealthy)
} else if s.Ready == s.Desired && s.Desired == s.Updated && s.Replicas == s.Desired {
hs.Status = HealthStatusRunning
- } else if s.Desired != s.Updated {
- hs.Status = HealthStatusUpdating
+ } else if !isStarting && s.Desired != s.Updated {
+ hs.Status = HealthStatusRollingOut
} else if s.Replicas > s.Desired {
hs.Status = HealthStatusScalingDown
} else if s.Replicas < s.Desired {
hs.Status = HealthStatusScalingUp
}
- if isStarting && hs.Health == HealthUnhealthy {
+ if s.Replicas != s.Desired || s.Replicas != s.Updated {
+ hs.Ready = false
+ }
+
+ if isStarting && (hs.Health == HealthUnhealthy || hs.Health == HealthWarning) {
hs.Health = HealthUnknown
}
diff --git a/pkg/health/health_test.go b/pkg/health/health_test.go
index 795d564..dd96002 100644
--- a/pkg/health/health_test.go
+++ b/pkg/health/health_test.go
@@ -143,21 +143,6 @@ func assertAppHealthWithOverwriteMsg(
assert.Equal(t, expectedMsg, health.Message)
}
-func assertAppHealthWithOverwrite(
- t *testing.T,
- yamlPath string,
- overwrites map[string]string,
- expectedStatus health.HealthStatusCode,
- expectedHealth health.Health,
- expectedReady bool,
-) {
- health, _ := getHealthStatus(yamlPath, t, overwrites)
- assert.NotNil(t, health)
- assert.Equal(t, expectedHealth, health.Health)
- assert.Equal(t, expectedReady, health.Ready)
- assert.Equal(t, expectedStatus, health.Status)
-}
-
func getHealthStatus(
yamlPath string,
t *testing.T,
@@ -315,88 +300,10 @@ func TestExternalSecrets(t *testing.T) {
assertAppHealthMsg(t, b+"healthy.yaml", "SecretSynced", health.HealthHealthy, true)
}
-func TestDeploymentHealth(t *testing.T) {
- assertAppHealthMsg(t, "./testdata/nginx.yaml", health.HealthStatusRunning, health.HealthHealthy, true, "1/1 ready")
- assertAppHealthMsg(
- t,
- "./deployment-scaled-up.yaml",
- health.HealthStatusRunning,
- health.HealthHealthy,
- true,
- "3/3 ready",
- )
-
- assertAppHealthMsg(
- t,
- "./deployment-rollout-failed.yaml",
- health.HealthStatusUpdating,
- health.HealthWarning,
- true,
- "1/2 ready, 1 updating",
- )
- assertAppHealthMsg(
- t,
- "./testdata/deployment-progressing.yaml",
- health.HealthStatusUpdating,
- health.HealthWarning,
- true,
- "1/2 ready, 1 updating",
- )
- assertAppHealthMsg(
- t,
- "./testdata/deployment-suspended.yaml",
- health.HealthStatusSuspended,
- health.HealthHealthy,
- false,
- "1/1 ready, 1 updating, 1 terminating",
- )
- assertAppHealthMsg(
- t,
- "./testdata/deployment-degraded.yaml",
- health.HealthStatusUpdating,
- health.HealthWarning,
- true,
- "1/2 ready, 1 updating",
- )
-
- assertAppHealthMsg(
- t,
- "./testdata/deployment-starting.yaml",
- health.HealthStatusStarting,
- health.HealthUnknown,
- true,
- "0/2 ready, 1 updating",
- )
- assertAppHealthMsg(
- t,
- "./testdata/deployment-scaling-down.yaml",
- health.HealthStatusScalingDown,
- health.HealthHealthy,
- true,
- "1/1 ready, 1 updating, 1 terminating",
- )
- assertAppHealthMsg(
- t,
- "./testdata/deployment-failed.yaml",
- "Failed Create",
- health.HealthUnhealthy,
- false,
- "0/1 ready",
- )
-}
-
func TestStatefulSetHealth(t *testing.T) {
+ starting := "./testdata/Kubernetes/StatefulSet/statefulset-starting.yaml"
assertAppHealthMsg(
- t,
- "./testdata/statefulset.yaml",
- health.HealthStatusRunning,
- health.HealthHealthy,
- true,
- "1/1 ready",
- )
- assertAppHealthMsg(
- t,
- "./testdata/statefulset-starting.yaml",
+ t, starting,
health.HealthStatusStarting,
health.HealthUnknown,
true,
@@ -406,7 +313,8 @@ func TestStatefulSetHealth(t *testing.T) {
)
assertAppHealthMsg(
t,
- "./testdata/statefulset-starting.yaml",
+ starting,
+
health.HealthStatusStarting,
health.HealthUnknown,
true,
@@ -416,7 +324,7 @@ func TestStatefulSetHealth(t *testing.T) {
)
assertAppHealthMsg(
t,
- "./testdata/statefulset-starting.yaml",
+ starting,
health.HealthStatusCrashLoopBackoff,
health.HealthUnhealthy,
true,
@@ -426,7 +334,7 @@ func TestStatefulSetHealth(t *testing.T) {
)
assertAppHealthMsg(
t,
- "./testdata/statefulset-starting.yaml",
+ starting,
health.HealthStatusCrashLoopBackoff,
health.HealthUnhealthy,
true,
@@ -439,7 +347,7 @@ func TestStatefulSetHealth(t *testing.T) {
func TestStatefulSetOnDeleteHealth(t *testing.T) {
assertAppHealthMsg(
t,
- "./testdata/statefulset-ondelete.yaml",
+ "./testdata/Kubernetes/StatefulSet/statefulset-ondelete.yaml",
"TerminatingStalled",
health.HealthWarning,
false,
@@ -536,16 +444,6 @@ func TestHPA(t *testing.T) {
)
}
-func TestReplicaSet(t *testing.T) {
- assertAppHealthWithOverwrite(t, "./testdata/replicaset-ittools.yml", map[string]string{
- "2024-08-03T06:06:18Z": time.Now().Add(-time.Minute * 2).UTC().Format("2006-01-02T15:04:05Z"),
- }, health.HealthStatusRunning, health.HealthHealthy, false)
-
- assertAppHealthWithOverwrite(t, "./testdata/replicaset-unhealthy-pods.yaml", map[string]string{
- "2024-10-21T11:20:19Z": time.Now().Add(-time.Minute * 2).UTC().Format("2006-01-02T15:04:05Z"),
- }, health.HealthStatusStarting, health.HealthUnknown, false)
-}
-
// func TestAPIService(t *testing.T) {
// assertAppHealthMsg(t, "./testdata/apiservice-v1-true.yaml", HealthStatusHealthy, health.HealthHealthy, true)
// assertAppHealthMsg(t, "./testdata/apiservice-v1-false.yaml", HealthStatusProgressing, health.HealthHealthy, true)
diff --git a/pkg/health/status.go b/pkg/health/status.go
index c9e02c2..fbe3cb2 100644
--- a/pkg/health/status.go
+++ b/pkg/health/status.go
@@ -257,3 +257,14 @@ func GetHealthFromStatus(k GenericStatus, statusMap StatusMap) (*HealthStatus, e
return health, nil
}
+
+func ListResourceTypes() []string {
+ types := []string{}
+ for k := range statusByKind {
+ if k == "default" {
+ continue
+ }
+ types = append(types, k)
+ }
+ return types
+}
diff --git a/pkg/health/testdata/deployment-degraded.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-degraded.yaml
similarity index 73%
rename from pkg/health/testdata/deployment-degraded.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-degraded.yaml
index 7f49967..21a9222 100644
--- a/pkg/health/testdata/deployment-degraded.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-degraded.yaml
@@ -2,9 +2,10 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- deployment.kubernetes.io/revision: "4"
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"guestbook-default"},"name":"guestbook-ui","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"guestbook-ui"}},"template":{"metadata":{"labels":{"app":"guestbook-ui","app.kubernetes.io/instance":"guestbook-default"}},"spec":{"containers":[{"image":"gcr.io/heptio-images/ks-guestbook-demo:0.3","name":"guestbook-ui","ports":[{"containerPort":80}]}]}}}}
+ expected-ready: "false"
+ expected-status: "Rolling Out"
+ expected-health: "warning"
+ expected-message: "1/2 ready, 1 updating"
creationTimestamp: 2018-07-18T04:40:44Z
generation: 4
labels:
@@ -55,7 +56,7 @@ status:
lastUpdateTime: 2018-07-18T04:48:48Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
- status: "True"
+ status: "false"
type: Available
- lastTransitionTime: 2018-07-18T06:29:23Z
lastUpdateTime: 2018-07-18T06:29:23Z
diff --git a/pkg/health/testdata/deployment-failed.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-failed.yaml
similarity index 88%
rename from pkg/health/testdata/deployment-failed.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-failed.yaml
index 6136a69..45ef505 100644
--- a/pkg/health/testdata/deployment-failed.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-failed.yaml
@@ -7,6 +7,11 @@ metadata:
control-plane: karina-operator
namespace: platform-system
annotations:
+ expected-status: Failed Create
+ expected-ready: "true"
+ expected-health: "unhealthy"
+ expected-message: 'pods "karina-c7585bd87-" is forbidden: error looking up service
+ account platform-system/karina: serviceaccount "karina" not found'
deployment.kubernetes.io/revision: "1"
creationTimestamp: 2023-05-10T08:11:03Z
spec:
diff --git a/pkg/health/testdata/deployment-progressing.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-progressing.yaml
similarity index 75%
rename from pkg/health/testdata/deployment-progressing.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-progressing.yaml
index cf61d45..a6ba5cc 100644
--- a/pkg/health/testdata/deployment-progressing.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-progressing.yaml
@@ -2,9 +2,11 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- deployment.kubernetes.io/revision: "4"
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"guestbook-default"},"name":"guestbook-ui","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"guestbook-ui"}},"template":{"metadata":{"labels":{"app":"guestbook-ui","app.kubernetes.io/instance":"guestbook-default"}},"spec":{"containers":[{"image":"gcr.io/heptio-images/ks-guestbook-demo:0.3","name":"guestbook-ui","ports":[{"containerPort":80}]}]}}}}
+ expected-status: Rolling Out
+ expected-health: healthy
+ expected-message: "1/2 ready, 1 updating"
+ expected-replicas: "2"
+ expted-ready: "false"
creationTimestamp: 2018-07-18T04:40:44Z
generation: 4
labels:
diff --git a/pkg/health/testdata/deployment-rollout-failed-unhealthy.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-rollout-failed-unhealthy.yaml
similarity index 94%
rename from pkg/health/testdata/deployment-rollout-failed-unhealthy.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-rollout-failed-unhealthy.yaml
index 512ee39..cbdab15 100644
--- a/pkg/health/testdata/deployment-rollout-failed-unhealthy.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-rollout-failed-unhealthy.yaml
@@ -2,6 +2,9 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: guestbook-ui
+ annotations:
+ expected-health: warning
+ expected-status: Rollout Failed
spec:
progressDeadlineSeconds: 600
replicas: 2
diff --git a/pkg/health/testdata/deployment-rollout-failed.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-rollout-failed.yaml
similarity index 90%
rename from pkg/health/testdata/deployment-rollout-failed.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-rollout-failed.yaml
index 86f87e1..5bf2914 100644
--- a/pkg/health/testdata/deployment-rollout-failed.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-rollout-failed.yaml
@@ -2,6 +2,11 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: guestbook-ui
+ annotations:
+ expected-ready: "false"
+ expected-status: "Rolling Out"
+ expected-health: "healthy"
+ expected-message: "1/2 ready, 1 updating"
spec:
progressDeadlineSeconds: 600
replicas: 2
diff --git a/pkg/health/testdata/deployment-scaled-up.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-scaled-up.yaml
similarity index 96%
rename from pkg/health/testdata/deployment-scaled-up.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-scaled-up.yaml
index 5e154b4..eaf8623 100644
--- a/pkg/health/testdata/deployment-scaled-up.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-scaled-up.yaml
@@ -10,9 +10,10 @@ metadata:
app.kubernetes.io/managed-by: Helm
namespace: podinfo
annotations:
- meta.helm.sh/release-name: podinfo
- meta.helm.sh/release-namespace: podinfo
- deployment.kubernetes.io/revision: "1"
+ expected-ready: "true"
+ expected-status: "Running"
+ expected-health: "healthy"
+ expected-message: "3/3 ready"
creationTimestamp: 2023-12-19T15:50:39Z
spec:
replicas: 3
diff --git a/pkg/health/testdata/deployment-scaling-down.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-scaling-down.yaml
similarity index 73%
rename from pkg/health/testdata/deployment-scaling-down.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-scaling-down.yaml
index ce7359f..0b073e3 100644
--- a/pkg/health/testdata/deployment-scaling-down.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-scaling-down.yaml
@@ -2,9 +2,10 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- deployment.kubernetes.io/revision: "4"
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"guestbook-default"},"name":"guestbook-ui","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"guestbook-ui"}},"template":{"metadata":{"labels":{"app":"guestbook-ui","app.kubernetes.io/instance":"guestbook-default"}},"spec":{"containers":[{"image":"gcr.io/heptio-images/ks-guestbook-demo:0.3","name":"guestbook-ui","ports":[{"containerPort":80}]}]}}}}
+ expected-ready: "false"
+ expected-status: "Scaling Down"
+ expected-health: "healthy"
+ expected-message: "1/1 ready, 1 updating, 1 terminating"
creationTimestamp: 2018-07-18T04:40:44Z
generation: 4
labels:
diff --git a/pkg/health/testdata/deployment-scaling-up.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-scaling-up.yaml
similarity index 93%
rename from pkg/health/testdata/deployment-scaling-up.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-scaling-up.yaml
index 9d18eca..9d1b46d 100644
--- a/pkg/health/testdata/deployment-scaling-up.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-scaling-up.yaml
@@ -1,9 +1,3 @@
-Config
-Changes1
-Insights0
-Relationships4
-Playbooks1
-Checks0
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -16,9 +10,11 @@ metadata:
app.kubernetes.io/managed-by: Helm
namespace: podinfo
annotations:
- meta.helm.sh/release-name: podinfo
- meta.helm.sh/release-namespace: podinfo
- deployment.kubernetes.io/revision: "1"
+ annotations:
+ expected-ready: "false"
+ expected-status: "Rolling Out"
+ expected-health: "warning"
+ expected-message: "1/3 ready, 1 updating"
creationTimestamp: 2023-12-19T15:50:39Z
spec:
replicas: 3
@@ -120,6 +116,6 @@ status:
status: "True"
message: ReplicaSet "podinfo-97c6d4b94" has successfully progressed.
readyReplicas: 1
- updatedReplicas: 3
+ updatedReplicas: 2
availableReplicas: 1
unavailableReplicas: 2
diff --git a/pkg/health/testdata/deployment-starting.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-starting.yaml
similarity index 95%
rename from pkg/health/testdata/deployment-starting.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-starting.yaml
index eec0a6d..a54a603 100644
--- a/pkg/health/testdata/deployment-starting.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-starting.yaml
@@ -5,6 +5,9 @@ metadata:
labels:
app.kubernetes.io/instance: guestbook-default
name: guestbook-ui
+ annotations:
+ expected-status: Starting
+ expected-health: unknown
namespace: default
spec:
progressDeadlineSeconds: 600
diff --git a/pkg/health/testdata/deployment-suspended.yaml b/pkg/health/testdata/Kubernetes/Deployment/deployment-suspended.yaml
similarity index 75%
rename from pkg/health/testdata/deployment-suspended.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/deployment-suspended.yaml
index e8c5a40..fe37baa 100644
--- a/pkg/health/testdata/deployment-suspended.yaml
+++ b/pkg/health/testdata/Kubernetes/Deployment/deployment-suspended.yaml
@@ -2,9 +2,10 @@ apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
- deployment.kubernetes.io/revision: "4"
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"guestbook-default"},"name":"guestbook-ui","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"guestbook-ui"}},"template":{"metadata":{"labels":{"app":"guestbook-ui","app.kubernetes.io/instance":"guestbook-default"}},"spec":{"containers":[{"image":"gcr.io/heptio-images/ks-guestbook-demo:0.3","name":"guestbook-ui","ports":[{"containerPort":80}]}]}}}}
+ expected-ready: "false"
+ expected-status: "Suspended"
+ expected-health: "healthy"
+ expected-message: "1/1 ready, 1 updating, 1 terminating"
creationTimestamp: 2018-07-18T04:40:44Z
generation: 4
labels:
diff --git a/pkg/health/testdata/nginx.yaml b/pkg/health/testdata/Kubernetes/Deployment/healthy.yaml
similarity index 100%
rename from pkg/health/testdata/nginx.yaml
rename to pkg/health/testdata/Kubernetes/Deployment/healthy.yaml
diff --git a/pkg/health/testdata/Kubernetes/Deployment/restart.yaml b/pkg/health/testdata/Kubernetes/Deployment/restart.yaml
new file mode 100644
index 0000000..0fa5a1e
--- /dev/null
+++ b/pkg/health/testdata/Kubernetes/Deployment/restart.yaml
@@ -0,0 +1,124 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ uid: 8d347012-945e-4e95-9b75-66aad2c923be
+ name: podinfo2
+ labels:
+ helm.sh/chart: podinfo-6.7.1
+ app.kubernetes.io/name: podinfo2
+ app.kubernetes.io/version: 6.7.1
+ helm.toolkit.fluxcd.io/name: podinfo2
+ app.kubernetes.io/managed-by: Helm
+ helm.toolkit.fluxcd.io/namespace: flux-092532
+ namespace: flux-092532
+ annotations:
+ expected-status: Updating
+ expected-ready: "false"
+ expected-health: "healthy"
+
+ meta.helm.sh/release-name: podinfo2
+ meta.helm.sh/release-namespace: flux-092532
+ deployment.kubernetes.io/revision: "2"
+ creationTimestamp: 2024-11-03T19:53:13Z
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: podinfo2
+ strategy:
+ type: RollingUpdate
+ rollingUpdate:
+ maxSurge: 25%
+ maxUnavailable: 1
+ template:
+ spec:
+ volumes:
+ - name: data
+ emptyDir: {}
+ dnsPolicy: ClusterFirst
+ containers:
+ - env:
+ - name: PODINFO_UI_COLOR
+ value: "#34577c"
+ name: podinfo
+ image: ghcr.io/stefanprodan/podinfo:6.7.1
+ ports:
+ - name: http
+ protocol: TCP
+ containerPort: 9898
+ - name: http-metrics
+ protocol: TCP
+ containerPort: 9797
+ - name: grpc
+ protocol: TCP
+ containerPort: 9999
+ command:
+ - ./podinfo
+ - --port=9898
+ - --cert-path=/data/cert
+ - --port-metrics=9797
+ - --grpc-port=9999
+ - --grpc-service-name=podinfo
+ - --level=info
+ - --random-delay=false
+ - --random-error=false
+ resources:
+ requests:
+ cpu: 1m
+ memory: 16Mi
+ volumeMounts:
+ - name: data
+ mountPath: /data
+ livenessProbe:
+ exec:
+ command:
+ - podcli
+ - check
+ - http
+ - localhost:9898/healthz
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 3
+ successThreshold: 1
+ initialDelaySeconds: 1
+ readinessProbe:
+ exec:
+ command:
+ - podcli
+ - check
+ - http
+ - localhost:9898/readyz
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 3
+ successThreshold: 1
+ initialDelaySeconds: 1
+ imagePullPolicy: IfNotPresent
+ terminationMessagePath: /dev/termination-log
+ terminationMessagePolicy: File
+ restartPolicy: Always
+ schedulerName: default-scheduler
+ securityContext: {}
+ terminationGracePeriodSeconds: 30
+ metadata:
+ labels:
+ app.kubernetes.io/name: podinfo2
+ annotations:
+ prometheus.io/port: "9898"
+ prometheus.io/scrape: "true"
+ kubectl.kubernetes.io/restartedAt: 2024-12-01T20:55:04Z
+ revisionHistoryLimit: 10
+ progressDeadlineSeconds: 600
+status:
+ replicas: 1
+ conditions:
+ - type: Available
+ reason: MinimumReplicasAvailable
+ status: "True"
+ message: Deployment has minimum availability.
+ - type: Progressing
+ reason: ReplicaSetUpdated
+ status: "True"
+ message: ReplicaSet "podinfo2-8c499d45b" is progressing.
+ updatedReplicas: 1
+ unavailableReplicas: 1
diff --git a/pkg/health/testdata/replicaset-ittools.yml b/pkg/health/testdata/Kubernetes/ReplicaSet/healthy.yml
similarity index 64%
rename from pkg/health/testdata/replicaset-ittools.yml
rename to pkg/health/testdata/Kubernetes/ReplicaSet/healthy.yml
index a1db08f..bb5dda8 100644
--- a/pkg/health/testdata/replicaset-ittools.yml
+++ b/pkg/health/testdata/Kubernetes/ReplicaSet/healthy.yml
@@ -2,11 +2,10 @@ apiVersion: apps/v1
kind: ReplicaSet
metadata:
annotations:
- deployment.kubernetes.io/desired-replicas: "1"
- deployment.kubernetes.io/max-replicas: "1"
- deployment.kubernetes.io/revision: "2"
- meta.helm.sh/release-name: ittools
- meta.helm.sh/release-namespace: default
+ expected-ready: "true"
+ expected-status: "Running"
+ expected-health: healthy"
+ expected-message: "1/1 ready"
creationTimestamp: "2024-08-03T06:06:18Z"
generation: 52
labels:
@@ -17,12 +16,12 @@ metadata:
name: ittools-5fbf458f49
namespace: default
ownerReferences:
- - apiVersion: apps/v1
- blockOwnerDeletion: true
- controller: true
- kind: Deployment
- name: ittools
- uid: d2beccff-8da9-42e8-8459-e7ff938b2ffd
+ - apiVersion: apps/v1
+ blockOwnerDeletion: true
+ controller: true
+ kind: Deployment
+ name: ittools
+ uid: d2beccff-8da9-42e8-8459-e7ff938b2ffd
resourceVersion: "96413911"
uid: c044b250-2445-4813-b00f-22b696c5fcf2
spec:
@@ -43,17 +42,17 @@ spec:
spec:
automountServiceAccountToken: true
containers:
- - image: corentinth/it-tools:latest
- imagePullPolicy: Always
- name: it-tools
- resources:
- limits:
- memory: 50Mi
- requests:
- cpu: 25m
- memory: 10Mi
- terminationMessagePath: /dev/termination-log
- terminationMessagePolicy: File
+ - image: corentinth/it-tools:latest
+ imagePullPolicy: Always
+ name: it-tools
+ resources:
+ limits:
+ memory: 50Mi
+ requests:
+ cpu: 25m
+ memory: 10Mi
+ terminationMessagePath: /dev/termination-log
+ terminationMessagePolicy: File
dnsPolicy: ClusterFirst
enableServiceLinks: false
restartPolicy: Always
diff --git a/pkg/health/testdata/replicaset-unhealthy-pods.yaml b/pkg/health/testdata/Kubernetes/ReplicaSet/starting.yaml
similarity index 100%
rename from pkg/health/testdata/replicaset-unhealthy-pods.yaml
rename to pkg/health/testdata/Kubernetes/ReplicaSet/starting.yaml
diff --git a/pkg/health/testdata/Kubernetes/ReplicaSet/unhealthy.yaml b/pkg/health/testdata/Kubernetes/ReplicaSet/unhealthy.yaml
new file mode 100644
index 0000000..e6fe2ab
--- /dev/null
+++ b/pkg/health/testdata/Kubernetes/ReplicaSet/unhealthy.yaml
@@ -0,0 +1,54 @@
+apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+ uid: f6579017-448f-425a-9645-ea3c93700948
+ name: failing-deployment-866585899d
+ labels:
+ app: failing-app
+ pod-template-hash: 866585899d
+ namespace: default
+ annotations:
+ expected-ready: "false"
+ expected-status: "CrashLoopBackOff"
+ expected-health: "unhealthy"
+ expected-message: "0/1 ready"
+ ownerReferences:
+ - uid: 1ab20b2b-e2c8-4e85-b7b6-5709ba594c0d
+ kind: Deployment
+ name: failing-deployment
+ apiVersion: apps/v1
+ controller: true
+ blockOwnerDeletion: true
+ creationTimestamp: "@now-1d"
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: failing-app
+ pod-template-hash: 866585899d
+ template:
+ spec:
+ dnsPolicy: ClusterFirst
+ containers:
+ - args:
+ - -c
+ - sleep 5 && exit 1
+ name: failing-container
+ image: busybox
+ command:
+ - /bin/sh
+ resources: {}
+ imagePullPolicy: Always
+ terminationMessagePath: /dev/termination-log
+ terminationMessagePolicy: File
+ restartPolicy: Always
+ schedulerName: default-scheduler
+ securityContext: {}
+ terminationGracePeriodSeconds: 30
+ metadata:
+ labels:
+ app: failing-app
+ pod-template-hash: 866585899d
+status:
+ replicas: 1
+ fullyLabeledReplicas: 1
diff --git a/pkg/health/testdata/statefulset-ondelete.yaml b/pkg/health/testdata/Kubernetes/StatefulSet/statefulset-ondelete.yaml
similarity index 63%
rename from pkg/health/testdata/statefulset-ondelete.yaml
rename to pkg/health/testdata/Kubernetes/StatefulSet/statefulset-ondelete.yaml
index 9f2adfa..ac743ca 100644
--- a/pkg/health/testdata/statefulset-ondelete.yaml
+++ b/pkg/health/testdata/Kubernetes/StatefulSet/statefulset-ondelete.yaml
@@ -2,8 +2,9 @@ apiVersion: apps/v1
kind: StatefulSet
metadata:
annotations:
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"apps/v1beta2","kind":"StatefulSet","metadata":{"annotations":{},"labels":{"app":"redis","app.kubernetes.io/instance":"redis","chart":"redis-3.6.5","heritage":"Tiller","release":"redis"},"name":"redis-master","namespace":"default"},"spec":{"selector":{"matchLabels":{"app":"redis","release":"redis","role":"master"}},"serviceName":"redis-master","template":{"metadata":{"labels":{"app":"redis","app.kubernetes.io/instance":"redis","release":"redis","role":"master"}},"spec":{"containers":[{"env":[{"name":"REDIS_REPLICATION_MODE","value":"master"},{"name":"REDIS_PASSWORD","valueFrom":{"secretKeyRef":{"key":"redis-password","name":"redis"}}},{"name":"REDIS_DISABLE_COMMANDS","value":"FLUSHDB,FLUSHALL"}],"image":"docker.io/bitnami/redis:4.0.10-debian-9","imagePullPolicy":"Always","livenessProbe":{"exec":{"command":["redis-cli","ping"]},"failureThreshold":5,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"redis","ports":[{"containerPort":6379,"name":"redis"}],"readinessProbe":{"exec":{"command":["redis-cli","ping"]},"failureThreshold":5,"initialDelaySeconds":5,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1},"resources":{},"volumeMounts":[{"mountPath":"/bitnami/redis/data","name":"redis-data"}]}],"securityContext":{"fsGroup":1001,"runAsUser":1001},"serviceAccountName":"default"}},"updateStrategy":{"type":"OnDelete"},"volumeClaimTemplates":[{"metadata":{"labels":{"app":"redis","chart":"redis-3.6.5","component":"master","heritage":"Tiller","release":"redis"},"name":"redis-data"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"8Gi"}}}}]}}
+ expected-ready: "false"
+ expected-status: "Terminating"
+ expected-message: "1/1 ready, 1 updating"
creationTimestamp: 2018-07-20T08:23:04Z
generation: 1
labels:
diff --git a/pkg/health/testdata/statefulset-starting.yaml b/pkg/health/testdata/Kubernetes/StatefulSet/statefulset-starting.yaml
similarity index 100%
rename from pkg/health/testdata/statefulset-starting.yaml
rename to pkg/health/testdata/Kubernetes/StatefulSet/statefulset-starting.yaml
diff --git a/pkg/health/testdata/statefulset.yaml b/pkg/health/testdata/Kubernetes/StatefulSet/statefulset.yaml
similarity index 63%
rename from pkg/health/testdata/statefulset.yaml
rename to pkg/health/testdata/Kubernetes/StatefulSet/statefulset.yaml
index 1ecd85e..a32b6bc 100644
--- a/pkg/health/testdata/statefulset.yaml
+++ b/pkg/health/testdata/Kubernetes/StatefulSet/statefulset.yaml
@@ -2,8 +2,10 @@ apiVersion: apps/v1
kind: StatefulSet
metadata:
annotations:
- kubectl.kubernetes.io/last-applied-configuration: |
- {"apiVersion":"apps/v1beta2","kind":"StatefulSet","metadata":{"annotations":{},"labels":{"app":"redis","app.kubernetes.io/instance":"redis","chart":"redis-3.6.5","heritage":"Tiller","release":"redis"},"name":"redis-master","namespace":"default"},"spec":{"selector":{"matchLabels":{"app":"redis","release":"redis","role":"master"}},"serviceName":"redis-master","template":{"metadata":{"labels":{"app":"redis","app.kubernetes.io/instance":"redis","release":"redis","role":"master"}},"spec":{"containers":[{"env":[{"name":"REDIS_REPLICATION_MODE","value":"master"},{"name":"REDIS_PASSWORD","valueFrom":{"secretKeyRef":{"key":"redis-password","name":"redis"}}},{"name":"REDIS_DISABLE_COMMANDS","value":"FLUSHDB,FLUSHALL"}],"image":"docker.io/bitnami/redis:4.0.10-debian-9","imagePullPolicy":"Always","livenessProbe":{"exec":{"command":["redis-cli","ping"]},"failureThreshold":5,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"redis","ports":[{"containerPort":6379,"name":"redis"}],"readinessProbe":{"exec":{"command":["redis-cli","ping"]},"failureThreshold":5,"initialDelaySeconds":5,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1},"resources":{},"volumeMounts":[{"mountPath":"/bitnami/redis/data","name":"redis-data"}]}],"securityContext":{"fsGroup":1001,"runAsUser":1001},"serviceAccountName":"default"}},"updateStrategy":{"type":"OnDelete"},"volumeClaimTemplates":[{"metadata":{"labels":{"app":"redis","chart":"redis-3.6.5","component":"master","heritage":"Tiller","release":"redis"},"name":"redis-data"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"8Gi"}}}}]}}
+ expected-ready: "true"
+ expected-status: "Running"
+ expected-health: "healthy"
+ expected-message: "1/1 ready"
creationTimestamp: 2018-07-20T08:23:04Z
generation: 1
labels:
diff --git a/pkg/lua/lua.go b/pkg/lua/lua.go
index 1319e28..a50f8db 100644
--- a/pkg/lua/lua.go
+++ b/pkg/lua/lua.go
@@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
+ "io/fs"
"os"
"path/filepath"
"strings"
@@ -428,6 +429,23 @@ func GetWildcardConfigMapKey(vm VM, gvk schema.GroupVersionKind) string {
return ""
}
+func ListResourceTypes() []string {
+ types := []string{}
+
+ _ = fs.WalkDir(resource_customizations.Embedded, ".", func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if d.IsDir() && !strings.HasSuffix(d.Name(), "testdata") && !strings.Contains(path, "/actions") &&
+ strings.Contains(path, "/") {
+ types = append(types, path)
+ }
+ return nil
+ })
+
+ return types
+}
+
func (vm VM) getPredefinedLuaScripts(objKey string, scriptFile string) (string, error) {
data, err := resource_customizations.Embedded.ReadFile(filepath.Join(objKey, scriptFile))
if err != nil {