mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-08-27 00:37:20 +00:00
Merge pull request #644 from replicatedhq/danj-custom-absent-messages
Allow custom messages to be passed if a deployment/statefulset is absent
This commit is contained in:
@@ -3,21 +3,31 @@ package analyzer
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
)
|
||||
|
||||
func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string, iconURI string, readyReplicas int) (*AnalyzeResult, error) {
|
||||
func commonStatus(outcomes []*troubleshootv1beta2.Outcome, name string, iconKey string, iconURI string, readyReplicas int, exists bool, resourceType string) (*AnalyzeResult, error) {
|
||||
result := &AnalyzeResult{
|
||||
Title: title,
|
||||
Title: fmt.Sprintf("%s Status", name),
|
||||
IconKey: iconKey,
|
||||
IconURI: iconURI,
|
||||
}
|
||||
|
||||
// ordering from the spec is important, the first one that matches returns
|
||||
for _, outcome := range outcomes {
|
||||
|
||||
if outcome.Fail != nil {
|
||||
|
||||
// if we're not checking that something is absent but it is, we should throw a default but meaningful error.
|
||||
if exists == false && outcome.Fail.When != "absent" {
|
||||
result.IsFail = true
|
||||
result.Message = fmt.Sprintf("The %s %q was not found", resourceType, name)
|
||||
result.URI = outcome.Fail.URI
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if outcome.Fail.When == "" {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
@@ -26,7 +36,18 @@ func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string
|
||||
return result, nil
|
||||
}
|
||||
|
||||
match, err := compareActualToWhen(outcome.Fail.When, readyReplicas)
|
||||
if outcome.Fail.When == "absent" {
|
||||
if exists == false {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
result.URI = outcome.Fail.URI
|
||||
return result, nil
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
match, err := compareActualToWhen(outcome.Fail.When, readyReplicas, exists)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse fail range")
|
||||
}
|
||||
@@ -39,6 +60,14 @@ func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string
|
||||
return result, nil
|
||||
}
|
||||
} else if outcome.Warn != nil {
|
||||
|
||||
if exists == false && outcome.Warn.When != "absent" {
|
||||
result.IsFail = true
|
||||
result.Message = fmt.Sprintf("The %s %q was not found", resourceType, name)
|
||||
result.URI = outcome.Fail.URI
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if outcome.Warn.When == "" {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
@@ -47,7 +76,18 @@ func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string
|
||||
return result, nil
|
||||
}
|
||||
|
||||
match, err := compareActualToWhen(outcome.Warn.When, readyReplicas)
|
||||
if outcome.Warn.When == "absent" {
|
||||
if exists == false {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
result.URI = outcome.Warn.URI
|
||||
return result, nil
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
match, err := compareActualToWhen(outcome.Warn.When, readyReplicas, exists)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse warn range")
|
||||
}
|
||||
@@ -60,6 +100,14 @@ func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string
|
||||
return result, nil
|
||||
}
|
||||
} else if outcome.Pass != nil {
|
||||
|
||||
if exists == false && outcome.Pass.When != "absent" {
|
||||
result.IsFail = true
|
||||
result.Message = fmt.Sprintf("The %s %q was not found", resourceType, name)
|
||||
result.URI = outcome.Fail.URI
|
||||
return result, nil
|
||||
}
|
||||
|
||||
if outcome.Pass.When == "" {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
@@ -68,7 +116,18 @@ func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string
|
||||
return result, nil
|
||||
}
|
||||
|
||||
match, err := compareActualToWhen(outcome.Pass.When, readyReplicas)
|
||||
if outcome.Pass.When == "absent" {
|
||||
if exists == false {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
result.URI = outcome.Pass.URI
|
||||
return result, nil
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
match, err := compareActualToWhen(outcome.Pass.When, readyReplicas, exists)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse pass range")
|
||||
}
|
||||
@@ -86,7 +145,7 @@ func commonStatus(outcomes []*troubleshootv1beta2.Outcome, title, iconKey string
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func compareActualToWhen(when string, actual int) (bool, error) {
|
||||
func compareActualToWhen(when string, actual int, exists bool) (bool, error) {
|
||||
parts := strings.Split(strings.TrimSpace(when), " ")
|
||||
|
||||
// we can make this a lot more flexible
|
||||
|
||||
@@ -26,6 +26,9 @@ func analyzeOneDeploymentStatus(analyzer *troubleshootv1beta2.DeploymentStatus,
|
||||
|
||||
var result *AnalyzeResult
|
||||
for _, collected := range files { // only 1 file here
|
||||
var exists bool = true
|
||||
var readyReplicas int
|
||||
|
||||
var deployments appsv1.DeploymentList
|
||||
if err := json.Unmarshal(collected, &deployments); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal deployment list")
|
||||
@@ -39,19 +42,15 @@ func analyzeOneDeploymentStatus(analyzer *troubleshootv1beta2.DeploymentStatus,
|
||||
}
|
||||
|
||||
if status == nil {
|
||||
// there's not an error, but maybe the requested deployment is not even deployed
|
||||
result = &AnalyzeResult{
|
||||
Title: fmt.Sprintf("%s Deployment Status", analyzer.Name),
|
||||
IconKey: "kubernetes_deployment_status",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/deployment-status.svg?w=17&h=17",
|
||||
IsFail: true,
|
||||
Message: fmt.Sprintf("The deployment %q was not found", analyzer.Name),
|
||||
}
|
||||
exists = false
|
||||
readyReplicas = 0
|
||||
} else {
|
||||
result, err = commonStatus(analyzer.Outcomes, fmt.Sprintf("%s Status", analyzer.Name), "kubernetes_deployment_status", "https://troubleshoot.sh/images/analyzer-icons/deployment-status.svg?w=17&h=17", int(status.ReadyReplicas))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to process status")
|
||||
}
|
||||
readyReplicas = int(status.ReadyReplicas)
|
||||
}
|
||||
|
||||
result, err = commonStatus(analyzer.Outcomes, analyzer.Name, "kubernetes_deployment_status", "https://troubleshoot.sh/images/analyzer-icons/deployment-status.svg?w=17&h=17", readyReplicas, exists, "deployment")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to process status")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,53 @@ func Test_deploymentStatus(t *testing.T) {
|
||||
expectResult []*AnalyzeResult
|
||||
files map[string][]byte
|
||||
}{
|
||||
{
|
||||
name: "1/1, fail when absent",
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "absent",
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 1",
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
},
|
||||
Namespace: "default",
|
||||
Name: "nonexistant-deployment",
|
||||
},
|
||||
expectResult: []*AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "nonexistant-deployment Status",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_deployment_status",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/deployment-status.svg?w=17&h=17",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"cluster-resources/deployments/default.json": []byte(defaultDeployments),
|
||||
"cluster-resources/deployments/monitoring.json": []byte(monitoringDeployments),
|
||||
"cluster-resources/deployments/kube-system.json": []byte(kubeSystemDeployments),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "1/1, pass when = 1",
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "absent",
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 1",
|
||||
@@ -55,6 +98,12 @@ func Test_deploymentStatus(t *testing.T) {
|
||||
name: "1/1, pass when = 2",
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "absent",
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 2",
|
||||
@@ -91,6 +140,12 @@ func Test_deploymentStatus(t *testing.T) {
|
||||
name: "1/1, pass when >= 2, warn when = 1, fail when 0",
|
||||
analyzer: troubleshootv1beta2.DeploymentStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "absent",
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: ">= 2",
|
||||
|
||||
@@ -26,6 +26,9 @@ func analyzeOneStatefulsetStatus(analyzer *troubleshootv1beta2.StatefulsetStatus
|
||||
|
||||
var result *AnalyzeResult
|
||||
for _, collected := range files { // only 1 file here
|
||||
var exists bool = true
|
||||
var readyReplicas int
|
||||
|
||||
var statefulsets appsv1.StatefulSetList
|
||||
if err := json.Unmarshal(collected, &statefulsets); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal statefulset list")
|
||||
@@ -40,15 +43,13 @@ func analyzeOneStatefulsetStatus(analyzer *troubleshootv1beta2.StatefulsetStatus
|
||||
}
|
||||
|
||||
if statefulset == nil {
|
||||
result = &AnalyzeResult{
|
||||
Title: fmt.Sprintf("%s Statefulset Status", analyzer.Name),
|
||||
IconKey: "kubernetes_statefulset_status",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/statefulset-status.svg?w=23&h=14",
|
||||
IsFail: true,
|
||||
Message: fmt.Sprintf("The statefulset %q was not found", analyzer.Name),
|
||||
}
|
||||
} else if len(analyzer.Outcomes) > 0 {
|
||||
result, err = commonStatus(analyzer.Outcomes, fmt.Sprintf("%s Status", analyzer.Name), "kubernetes_statefulset_status", "https://troubleshoot.sh/images/analyzer-icons/statefulset-status.svg?w=23&h=14", int(statefulset.Status.ReadyReplicas))
|
||||
exists = false
|
||||
readyReplicas = 0
|
||||
} else {
|
||||
readyReplicas = int(statefulset.Status.ReadyReplicas)
|
||||
}
|
||||
if len(analyzer.Outcomes) > 0 {
|
||||
result, err = commonStatus(analyzer.Outcomes, analyzer.Name, "kubernetes_statefulset_status", "https://troubleshoot.sh/images/analyzer-icons/statefulset-status.svg?w=23&h=14", readyReplicas, exists, "statefulset")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to process status")
|
||||
}
|
||||
|
||||
@@ -15,6 +15,41 @@ func Test_analyzeStatefulsetStatus(t *testing.T) {
|
||||
expectResult []*AnalyzeResult
|
||||
files map[string][]byte
|
||||
}{
|
||||
{
|
||||
name: "fail when absent",
|
||||
analyzer: troubleshootv1beta2.StatefulsetStatus{
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "absent",
|
||||
Message: "fail",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "= 1",
|
||||
Message: "pass",
|
||||
},
|
||||
},
|
||||
},
|
||||
Namespace: "default",
|
||||
Name: "nonexistant",
|
||||
},
|
||||
expectResult: []*AnalyzeResult{
|
||||
{
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "nonexistant Status",
|
||||
Message: "fail",
|
||||
IconKey: "kubernetes_statefulset_status",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/statefulset-status.svg?w=23&h=14",
|
||||
},
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"cluster-resources/statefulsets/default.json": []byte(defaultStatefulSets),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "analyze all statefulsets",
|
||||
analyzer: troubleshootv1beta2.StatefulsetStatus{},
|
||||
|
||||
Reference in New Issue
Block a user