Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/v2 #17

Merged
merged 5 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
submodules: recursive

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ updates:
directory: /
schedule:
interval: daily

- package-ecosystem: gitsubmodule
directory: /
schedule:
interval: monthly
20 changes: 20 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Lint
on:
pull_request:

jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: 1.20.x
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
args: --timeout 5m0s --verbose
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:
jobs:
semantic-release:
permissions:
contents: write # for codfish/semantic-release-action to create release tags
contents: write # for codfish/semantic-release-action to create release tags
runs-on: ubuntu-latest
outputs:
release-version: ${{ steps.semantic.outputs.release-version }}
Expand All @@ -22,6 +22,8 @@ jobs:
egress-policy: audit

- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
submodules: true
- uses: codfish/semantic-release-action@cbd853afe12037afb1306caca9d6b1ab6a58cf2a # v1.10.0
id: semantic
env:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
name: Test
jobs:
test:
strategy:
matrix:
platform: [ubuntu-latest]
go-version:
- 1.20.x
runs-on: ${{ matrix.platform }}
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: recursive
- name: Test
run: go test ./...
env:
ASSUME_NO_MOVING_GC_UNSAFE_RISK_IT_WITH: go1.20
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.PHONY: test
test:
go test ./... -v

.PHONY: lint
lint:
golangci-lint run
2 changes: 1 addition & 1 deletion argo-cd
Submodule argo-cd updated 1197 files
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/flanksource/is-healthy

go 1.19
go 1.20

require (
github.com/gobwas/glob v0.2.3
Expand Down
104 changes: 56 additions & 48 deletions pkg/health/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
)

type Health string

const (
HealthHealthy Health = "healthy"
HealthUnhealthy Health = "unhealthy"
HealthUnknown Health = "unknown"
HealthWarning Health = "warning"
)

// Represents resource health status
type HealthStatusCode string

Expand All @@ -24,20 +33,33 @@ const (
// Indicates that resource is missing in the cluster.
HealthStatusMissing HealthStatusCode = "Missing"

HealthStatusCreating HealthStatusCode = "Creating"
HealthStatusDeleted HealthStatusCode = "Deleted"
HealthStatusDeleting HealthStatusCode = "Deleting"
HealthStatusError HealthStatusCode = "Error"
HealthStatusInaccesible HealthStatusCode = "Inaccesible"
HealthStatusInfo HealthStatusCode = "Info"
HealthStatusPending HealthStatusCode = "Pending"
HealthStatusMaintenance HealthStatusCode = "Maintenance"
HealthStatusScaling HealthStatusCode = "Scaling"
HealthStatusUnhealthy HealthStatusCode = "Unhealthy"
HealthStatusUpdating HealthStatusCode = "Updating"
HealthStatusWarning HealthStatusCode = "Warning"
HealthStatusStopped HealthStatusCode = "Stopped"
HealthStatusStopping HealthStatusCode = "Stopping"
HealthStatusCompleted HealthStatusCode = "Completed"
HealthStatusCrashLoopBackoff HealthStatusCode = "CrashLoopBackOff"
HealthStatusCreating HealthStatusCode = "Creating"
HealthStatusDeleted HealthStatusCode = "Deleted"
HealthStatusDeleting HealthStatusCode = "Deleting"
HealthStatusError HealthStatusCode = "Error"
HealthStatusRolloutFailed HealthStatusCode = "Rollout Failed"
HealthStatusInaccesible HealthStatusCode = "Inaccesible"
HealthStatusInfo HealthStatusCode = "Info"
HealthStatusPending HealthStatusCode = "Pending"
HealthStatusMaintenance HealthStatusCode = "Maintenance"
HealthStatusScaling HealthStatusCode = "Scaling"
HealthStatusRestart HealthStatusCode = "Restarting"
HealthStatusStarting HealthStatusCode = "Starting"

HealthStatusScalingUp HealthStatusCode = "Scaling Up"
HealthStatusScaledToZero HealthStatusCode = "Scaled to Zero"
HealthStatusScalingDown HealthStatusCode = "Scaling Down"
HealthStatusRunning HealthStatusCode = "Running"

HealthStatusRollingOut HealthStatusCode = "Rolling Out"

HealthStatusUnhealthy HealthStatusCode = "Unhealthy"
HealthStatusUpdating HealthStatusCode = "Updating"
HealthStatusWarning HealthStatusCode = "Warning"
HealthStatusStopped HealthStatusCode = "Stopped"
HealthStatusStopping HealthStatusCode = "Stopping"
)

// Implements custom health assessment that overrides built-in assessment
Expand Down Expand Up @@ -72,11 +94,15 @@ func IsWorse(current, new HealthStatusCode) bool {

// GetResourceHealth returns the health of a k8s resource
func GetResourceHealth(obj *unstructured.Unstructured, healthOverride HealthOverride) (health *HealthStatus, err error) {
if obj.GetDeletionTimestamp() != nil {
return &HealthStatus{
Status: HealthStatusProgressing,
Message: "Pending deletion",
}, nil
if healthCheck := GetHealthCheckFunc(obj.GroupVersionKind()); healthCheck != nil {
if health, err = healthCheck(obj); err != nil {
health = &HealthStatus{
Status: HealthStatusUnknown,
Message: err.Error(),
}
} else {
return health, nil
}
}

if healthOverride != nil {
Expand All @@ -93,18 +119,16 @@ func GetResourceHealth(obj *unstructured.Unstructured, healthOverride HealthOver
}
}

if healthCheck := GetHealthCheckFunc(obj.GroupVersionKind()); healthCheck != nil {
if health, err = healthCheck(obj); err != nil {
health = &HealthStatus{
Status: HealthStatusUnknown,
Message: err.Error(),
}
}
if obj.GetDeletionTimestamp() != nil {
return &HealthStatus{
Status: HealthStatusDeleting,
}, nil
}

if health == nil {
return &HealthStatus{
Status: HealthStatusUnknown,
Ready: true,
}, nil
}
return health, err
Expand Down Expand Up @@ -140,28 +164,10 @@ func GetHealthCheckFunc(gvk schema.GroupVersionKind) func(obj *unstructured.Unst
case "Application":
return getArgoApplicationHealth
}
case "kustomize.toolkit.fluxcd.io":
switch gvk.Kind {
case "Kustomization":
return getFluxKustomizationHealth
}
case "helm.toolkit.fluxcd.io":
switch gvk.Kind {
case "HelmRelease":
return getFluxHelmReleaseHealth
}
case "source.toolkit.fluxcd.io":
switch gvk.Kind {
case "HelmRepository", "GitRepository":
return getFluxRepositoryHealth
}

// case "apiregistration.k8s.io":
// switch gvk.Kind {
// case APIServiceKind:
// return getAPIServiceHealth
// }

case "kustomize.toolkit.fluxcd.io", "helm.toolkit.fluxcd.io", "source.toolkit.fluxcd.io":
return GetDefaultHealth
case "cert-manager.io":
return GetDefaultHealth
case "networking.k8s.io":
switch gvk.Kind {
case IngressKind:
Expand All @@ -182,6 +188,8 @@ func GetHealthCheckFunc(gvk schema.GroupVersionKind) func(obj *unstructured.Unst
switch gvk.Kind {
case JobKind:
return getJobHealth
case CronJobKind:
return getCronJobHealth
}
case "autoscaling":
switch gvk.Kind {
Expand Down
64 changes: 35 additions & 29 deletions pkg/health/health_argo.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,49 @@ func GetArgoWorkflowHealth(obj *unstructured.Unstructured) (*HealthStatus, error
return nil, err
}
switch wf.Status.Phase {
case "", nodePending, nodeRunning:
return &HealthStatus{Status: HealthStatusProgressing, Message: wf.Status.Message}, nil
case "", nodePending:
return &HealthStatus{Health: HealthHealthy, Status: HealthStatusProgressing, Message: wf.Status.Message}, nil
case nodeRunning:
return &HealthStatus{Ready: true, Health: HealthHealthy, Status: HealthStatusProgressing, Message: wf.Status.Message}, nil
case nodeSucceeded:
return &HealthStatus{Status: HealthStatusHealthy, Message: wf.Status.Message}, nil
return &HealthStatus{Ready: true, Health: HealthHealthy, Status: HealthStatusHealthy, Message: wf.Status.Message}, nil
case nodeFailed, nodeError:
return &HealthStatus{Status: HealthStatusDegraded, Message: wf.Status.Message}, nil
return &HealthStatus{Health: HealthUnhealthy, Status: HealthStatusDegraded, Message: wf.Status.Message}, nil
}
return &HealthStatus{Status: HealthStatusUnknown, Message: wf.Status.Message}, nil
return &HealthStatus{Health: HealthUnknown, Status: HealthStatusUnknown, Message: wf.Status.Message}, nil
}

// An agnostic workflow object only considers Status.Phase and Status.Message. It is agnostic to the API version or any
// other fields.
type argoApplication struct {
Status struct {
Health HealthStatus
}
}
const (
SyncStatusCodeSynced = "Synced"
)

func getArgoApplicationHealth(obj *unstructured.Unstructured) (*HealthStatus, error) {
var app argoApplication
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &app); err != nil {
return nil, err
hs := &HealthStatus{Health: HealthUnknown}
var status map[string]interface{}

status, ok := obj.Object["status"].(map[string]interface{})
if !ok {
return hs, nil
}

switch app.Status.Health.Status {
case HealthStatusProgressing:
return &HealthStatus{Status: HealthStatusProgressing, Message: app.Status.Health.Message}, nil
case HealthStatusHealthy:
return &HealthStatus{Status: HealthStatusHealthy, Message: app.Status.Health.Message}, nil
case HealthStatusSuspended:
return &HealthStatus{Status: HealthStatusSuspended, Message: app.Status.Health.Message}, nil
case HealthStatusDegraded:
return &HealthStatus{Status: HealthStatusDegraded, Message: app.Status.Health.Message}, nil
case HealthStatusMissing:
return &HealthStatus{Status: HealthStatusMissing, Message: app.Status.Health.Message}, nil
case HealthStatusUnknown:
return &HealthStatus{Status: HealthStatusUnknown, Message: app.Status.Health.Message}, nil
if sync, ok := status["sync"].(map[string]interface{}); ok {
hs.Ready = sync["status"] == SyncStatusCodeSynced
}
if health, ok := status["health"].(map[string]interface{}); ok {
if message, ok := health["message"]; ok {
hs.Message = message.(string)
}
if argoHealth, ok := health["status"]; ok {
hs.Status = HealthStatusCode(argoHealth.(string))
switch hs.Status {
case HealthStatusHealthy:
hs.Health = HealthHealthy
case HealthStatusDegraded:
hs.Health = HealthUnhealthy
case HealthStatusUnknown, HealthStatusMissing, HealthStatusProgressing, HealthStatusSuspended:
hs.Health = HealthUnknown
}
}
}
return &HealthStatus{Status: HealthStatusUnknown, Message: app.Status.Health.Message}, nil
return hs, nil
}
6 changes: 3 additions & 3 deletions pkg/health/health_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ var awsStatusMap = map[string]map[string]HealthStatusCode{
"maintenance": HealthStatusMaintenance,
"modifying": HealthStatusUpdating,
"moving-to-vpc": HealthStatusMaintenance,
"rebooting": HealthStatusStopping,
"rebooting": HealthStatusRestart,
"resetting-master-credentials": HealthStatusMaintenance,
"renaming": HealthStatusMaintenance,
"restore-error": HealthStatusError,
"starting": HealthStatusProgressing,
"starting": HealthStatusStarting,
"stopped": HealthStatusStopped,
"stopping": HealthStatusStopping,
"storage-config-upgrade": HealthStatusUpdating,
Expand All @@ -88,7 +88,7 @@ var awsStatusMap = map[string]map[string]HealthStatusCode{

AWSResourceTypeELB: {
"active": HealthStatusHealthy,
"provisioning": HealthStatusProgressing,
"provisioning": HealthStatusCreating,
"active_impaired": HealthStatusWarning,
"failed": HealthStatusError,
},
Expand Down
Loading
Loading