diff --git a/pkg/schema/v1/deployment.go b/pkg/schema/v1/deployment.go index 7ed34dc5..097ae39b 100644 --- a/pkg/schema/v1/deployment.go +++ b/pkg/schema/v1/deployment.go @@ -1,10 +1,12 @@ package v1 import ( + "fmt" "github.com/icinga/icinga-go-library/types" "github.com/icinga/icinga-kubernetes/pkg/database" "github.com/icinga/icinga-kubernetes/pkg/strcase" kappsv1 "k8s.io/api/apps/v1" + kcorev1 "k8s.io/api/core/v1" kmetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kruntime "k8s.io/apimachinery/pkg/runtime" kserializer "k8s.io/apimachinery/pkg/runtime/serializer" @@ -25,6 +27,8 @@ type Deployment struct { AvailableReplicas int32 UnavailableReplicas int32 Yaml string + IcingaState IcingaState + IcingaStateReason string Conditions []DeploymentCondition `db:"-"` Labels []Label `db:"-"` DeploymentLabels []DeploymentLabel `db:"-"` @@ -75,6 +79,7 @@ func (d *Deployment) Obtain(k8s kmetav1.Object) { d.AvailableReplicas = deployment.Status.AvailableReplicas d.ReadyReplicas = deployment.Status.ReadyReplicas d.UnavailableReplicas = deployment.Status.UnavailableReplicas + d.IcingaState, d.IcingaStateReason = d.getIcingaState() for _, condition := range deployment.Status.Conditions { d.Conditions = append(d.Conditions, DeploymentCondition{ @@ -108,6 +113,40 @@ func (d *Deployment) Obtain(k8s kmetav1.Object) { d.Yaml = string(output) } +func (d *Deployment) getIcingaState() (IcingaState, string) { + if gracePeriodReason := IsWithinGracePeriod(d); gracePeriodReason != nil { + return Ok, *gracePeriodReason + } + + for _, condition := range d.Conditions { + if condition.Type == string(kappsv1.DeploymentAvailable) && condition.Status != string(kcorev1.ConditionTrue) { + reason := fmt.Sprintf("Deployment %s/%s is not available: %s", d.Namespace, d.Name, condition.Message) + + return Critical, reason + } + if condition.Type == string(kappsv1.ReplicaSetReplicaFailure) && condition.Status != string(kcorev1.ConditionTrue) { + reason := fmt.Sprintf("Deployment %s/%s has replica failure: %s", d.Namespace, d.Name, condition.Message) + + return Critical, reason + } + } + + switch { + case d.UnavailableReplicas > 0: + reason := fmt.Sprintf("Deployment %s/%s has %d unavailable replicas", d.Namespace, d.Name, d.UnavailableReplicas) + + return Critical, reason + case d.AvailableReplicas < d.DesiredReplicas: + reason := fmt.Sprintf("Deployment %s/%s only has %d out of %d desired replicas available", d.Namespace, d.Name, d.AvailableReplicas, d.DesiredReplicas) + + return Warning, reason + default: + reason := fmt.Sprintf("Deployment %s/%s has all %d desired replicas available", d.Namespace, d.Name, d.DesiredReplicas) + + return Ok, reason + } +} + func (d *Deployment) Relations() []database.Relation { fk := database.WithForeignKey("deployment_uuid") diff --git a/schema/mysql/schema.sql b/schema/mysql/schema.sql index 85a18094..446c3ddb 100644 --- a/schema/mysql/schema.sql +++ b/schema/mysql/schema.sql @@ -180,6 +180,8 @@ CREATE TABLE deployment ( available_replicas int unsigned NOT NULL, unavailable_replicas int unsigned NOT NULL, yaml mediumblob DEFAULT NULL, + icinga_state enum('ok', 'warning', 'critical', 'unknown') COLLATE utf8mb4_unicode_ci NOT NULL, + icinga_state_reason text NOT NULL, created bigint unsigned NOT NULL, PRIMARY KEY (uuid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;