mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-02-14 10:19:54 +00:00
feat(analyzer): allow templating for Node Resources Analyzer (#1605)
* feat(analyzer): allow templating for Node Resources Analyzer
This commit is contained in:
@@ -1166,10 +1166,10 @@ spec:
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
architecture:
|
||||
type: string
|
||||
cpuAllocatable:
|
||||
type: string
|
||||
cpuArchitecture:
|
||||
type: string
|
||||
cpuCapacity:
|
||||
type: string
|
||||
ephemeralStorageAllocatable:
|
||||
|
||||
@@ -1166,10 +1166,10 @@ spec:
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
architecture:
|
||||
type: string
|
||||
cpuAllocatable:
|
||||
type: string
|
||||
cpuArchitecture:
|
||||
type: string
|
||||
cpuCapacity:
|
||||
type: string
|
||||
ephemeralStorageAllocatable:
|
||||
|
||||
@@ -1197,10 +1197,10 @@ spec:
|
||||
type: BoolString
|
||||
filters:
|
||||
properties:
|
||||
architecture:
|
||||
type: string
|
||||
cpuAllocatable:
|
||||
type: string
|
||||
cpuArchitecture:
|
||||
type: string
|
||||
cpuCapacity:
|
||||
type: string
|
||||
ephemeralStorageAllocatable:
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
util "github.com/replicatedhq/troubleshoot/internal/util"
|
||||
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -18,12 +19,16 @@ type AnalyzeNodeResources struct {
|
||||
analyzer *troubleshootv1beta2.NodeResources
|
||||
}
|
||||
|
||||
type NodeResourceMsg struct {
|
||||
*troubleshootv1beta2.NodeResourceFilters
|
||||
NodeCount int
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeResources) Title() string {
|
||||
title := a.analyzer.CheckName
|
||||
if title == "" {
|
||||
title = "Node Resources"
|
||||
}
|
||||
|
||||
return title
|
||||
}
|
||||
|
||||
@@ -41,6 +46,7 @@ func (a *AnalyzeNodeResources) Analyze(getFile getCollectedFileContents, findFil
|
||||
}
|
||||
|
||||
func (a *AnalyzeNodeResources) analyzeNodeResources(analyzer *troubleshootv1beta2.NodeResources, getCollectedFileContents func(string) ([]byte, error)) (*AnalyzeResult, error) {
|
||||
|
||||
collected, err := getCollectedFileContents(fmt.Sprintf("%s/%s.json", constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_NODES))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get contents of nodes.json")
|
||||
@@ -70,6 +76,10 @@ func (a *AnalyzeNodeResources) analyzeNodeResources(analyzer *troubleshootv1beta
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
}
|
||||
|
||||
nodeMsg := NodeResourceMsg{
|
||||
analyzer.Filters, len(matchingNodes),
|
||||
}
|
||||
|
||||
for _, outcome := range analyzer.Outcomes {
|
||||
if outcome.Fail != nil {
|
||||
isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Fail.When, matchingNodes)
|
||||
@@ -79,9 +89,11 @@ func (a *AnalyzeNodeResources) analyzeNodeResources(analyzer *troubleshootv1beta
|
||||
|
||||
if isWhenMatch {
|
||||
result.IsFail = true
|
||||
result.Message = outcome.Fail.Message
|
||||
result.Message, err = util.RenderTemplate(outcome.Fail.Message, nodeMsg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render message template")
|
||||
}
|
||||
result.URI = outcome.Fail.URI
|
||||
|
||||
return result, nil
|
||||
}
|
||||
} else if outcome.Warn != nil {
|
||||
@@ -92,7 +104,10 @@ func (a *AnalyzeNodeResources) analyzeNodeResources(analyzer *troubleshootv1beta
|
||||
|
||||
if isWhenMatch {
|
||||
result.IsWarn = true
|
||||
result.Message = outcome.Warn.Message
|
||||
result.Message, err = util.RenderTemplate(outcome.Warn.Message, nodeMsg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render message template")
|
||||
}
|
||||
result.URI = outcome.Warn.URI
|
||||
|
||||
return result, nil
|
||||
@@ -105,7 +120,10 @@ func (a *AnalyzeNodeResources) analyzeNodeResources(analyzer *troubleshootv1beta
|
||||
|
||||
if isWhenMatch {
|
||||
result.IsPass = true
|
||||
result.Message = outcome.Pass.Message
|
||||
result.Message, err = util.RenderTemplate(outcome.Pass.Message, nodeMsg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to render message template")
|
||||
}
|
||||
result.URI = outcome.Pass.URI
|
||||
|
||||
return result, nil
|
||||
@@ -373,8 +391,8 @@ func nodeMatchesFilters(node corev1.Node, filters *troubleshootv1beta2.NodeResou
|
||||
}
|
||||
}
|
||||
|
||||
if filters.Architecture != "" {
|
||||
parsed := filters.Architecture
|
||||
if filters.CPUArchitecture != "" {
|
||||
parsed := filters.CPUArchitecture
|
||||
|
||||
if !strings.EqualFold(node.Status.NodeInfo.Architecture, parsed) {
|
||||
return false, nil
|
||||
|
||||
@@ -445,7 +445,7 @@ func Test_nodeMatchesFilters(t *testing.T) {
|
||||
name: "true when cpu arch is amd64",
|
||||
node: node,
|
||||
filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
Architecture: "amd64",
|
||||
CPUArchitecture: "amd64",
|
||||
},
|
||||
expectResult: true,
|
||||
},
|
||||
@@ -453,7 +453,7 @@ func Test_nodeMatchesFilters(t *testing.T) {
|
||||
name: "false when cpu arch is not amd64",
|
||||
node: node,
|
||||
filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
Architecture: "armhf",
|
||||
CPUArchitecture: "armhf",
|
||||
},
|
||||
expectResult: false,
|
||||
},
|
||||
@@ -751,7 +751,44 @@ func Test_analyzeNodeResources(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
Architecture: "amd64",
|
||||
CPUArchitecture: "amd64",
|
||||
},
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsFail: false,
|
||||
IsWarn: false,
|
||||
Title: "amd64-exists",
|
||||
Message: "There is a node with at least 8 cores on amd64 arch",
|
||||
URI: "",
|
||||
IconKey: "kubernetes_node_resources",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "at least 8 cores on amd64 with message templating", // filter for a node with enough amd64 cores with message templating
|
||||
analyzer: &troubleshootv1beta2.NodeResources{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "amd64-exists",
|
||||
},
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "max(cpuCapacity) < 8",
|
||||
Message: "There isn't a node with 8 or more cores on {{ .CPUArchitecture }} arch",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "max(cpuCapacity) >= 8",
|
||||
Message: "There is a node with at least 8 cores on {{ .CPUArchitecture }} arch",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
CPUArchitecture: "amd64",
|
||||
},
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
@@ -898,6 +935,162 @@ func Test_analyzeNodeResources(t *testing.T) {
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "8 cores in nodes with at least 8gb of ram with message templating", // validate that filtering based on memory capacity works with message templating
|
||||
analyzer: &troubleshootv1beta2.NodeResources{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "memory filter",
|
||||
},
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "sum(cpuCapacity) < 8",
|
||||
Message: "less than 8 CPUs in nodes with {{ .MemoryCapacity }} of ram",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Warn: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "sum(cpuCapacity) = 8",
|
||||
Message: "exactly 8 CPUs total in nodes with {{ .MemoryCapacity }} of ram",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "sum(cpuCapacity) > 8",
|
||||
Message: "more than 8 CPUs in nodes with {{ .MemoryCapacity }} of ram",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
MemoryCapacity: "8Gi",
|
||||
},
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsFail: false,
|
||||
IsWarn: false,
|
||||
Title: "memory filter",
|
||||
Message: "more than 8 CPUs in nodes with 8Gi of ram",
|
||||
URI: "",
|
||||
IconKey: "kubernetes_node_resources",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "at least 1 node on arm64 with message templating", // filter for arm64 nodes with message templating
|
||||
analyzer: &troubleshootv1beta2.NodeResources{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "arm64-exists",
|
||||
},
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "count() < 3",
|
||||
Message: "This application requires at least 3 nodes. {{ .CPUArchitecture }}, it should only return the {{ .NodeCount }} nodes that match that filter",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "count() >= 3",
|
||||
Message: "There are {{ .NodeCount }} nodes that match that filter",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
CPUArchitecture: "arm64",
|
||||
},
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: false,
|
||||
IsFail: true,
|
||||
IsWarn: false,
|
||||
Title: "arm64-exists",
|
||||
Message: "This application requires at least 3 nodes. arm64, it should only return the 0 nodes that match that filter",
|
||||
URI: "",
|
||||
IconKey: "kubernetes_node_resources",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "at least 1 node on amd64 with message templating", // filter for amd64 nodes with message templating
|
||||
analyzer: &troubleshootv1beta2.NodeResources{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "amd64-exists",
|
||||
},
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "count() < 3",
|
||||
Message: "This application requires at least 3 nodes. {{ .CPUArchitecture }}, it should only return the {{ .NodeCount }} nodes that match that filter",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "count() >= 3",
|
||||
Message: "There are {{ .NodeCount }} nodes that match that filter",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
CPUArchitecture: "amd64",
|
||||
},
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsFail: false,
|
||||
IsWarn: false,
|
||||
Title: "amd64-exists",
|
||||
Message: "There are 6 nodes that match that filter",
|
||||
URI: "",
|
||||
IconKey: "kubernetes_node_resources",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Only 5 Nodes with amd64 and 2 CPU with message templating", // filter for amd64 and 2 CPU nodes with message templating
|
||||
analyzer: &troubleshootv1beta2.NodeResources{
|
||||
AnalyzeMeta: troubleshootv1beta2.AnalyzeMeta{
|
||||
CheckName: "amd64-exists",
|
||||
},
|
||||
Outcomes: []*troubleshootv1beta2.Outcome{
|
||||
{
|
||||
Fail: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "count() < 3",
|
||||
Message: "This application requires at least 3 nodes. {{ .CPUArchitecture }}, it should only return the {{ .NodeCount }} nodes that match that filter",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Pass: &troubleshootv1beta2.SingleOutcome{
|
||||
When: "count() >= 3",
|
||||
Message: "There are {{ .NodeCount }} nodes that match that filter {{ .CPUArchitecture }} and {{ .CPUCapacity }} CPU cores",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: &troubleshootv1beta2.NodeResourceFilters{
|
||||
CPUArchitecture: "amd64",
|
||||
CPUCapacity: "2",
|
||||
},
|
||||
},
|
||||
want: &AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsFail: false,
|
||||
IsWarn: false,
|
||||
Title: "amd64-exists",
|
||||
Message: "There are 5 nodes that match that filter amd64 and 2 CPU cores",
|
||||
URI: "",
|
||||
IconKey: "kubernetes_node_resources",
|
||||
IconURI: "https://troubleshoot.sh/images/analyzer-icons/node-resources.svg?w=16&h=18",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "no pass or fail", // validate that the pass message is not always shown
|
||||
|
||||
@@ -120,7 +120,7 @@ type NodeResources struct {
|
||||
}
|
||||
|
||||
type NodeResourceFilters struct {
|
||||
Architecture string `json:"architecture,omitempty" yaml:"cpuArchitecture,omitempty"`
|
||||
CPUArchitecture string `json:"cpuArchitecture,omitempty" yaml:"cpuArchitecture,omitempty"`
|
||||
CPUCapacity string `json:"cpuCapacity,omitempty" yaml:"cpuCapacity,omitempty"`
|
||||
CPUAllocatable string `json:"cpuAllocatable,omitempty" yaml:"cpuAllocatable,omitempty"`
|
||||
MemoryCapacity string `json:"memoryCapacity,omitempty" yaml:"memoryCapacity,omitempty"`
|
||||
|
||||
@@ -1755,10 +1755,10 @@
|
||||
"filters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"cpuAllocatable": {
|
||||
"type": "string"
|
||||
},
|
||||
"cpuAllocatable": {
|
||||
"cpuArchitecture": {
|
||||
"type": "string"
|
||||
},
|
||||
"cpuCapacity": {
|
||||
|
||||
@@ -1755,10 +1755,10 @@
|
||||
"filters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"cpuAllocatable": {
|
||||
"type": "string"
|
||||
},
|
||||
"cpuAllocatable": {
|
||||
"cpuArchitecture": {
|
||||
"type": "string"
|
||||
},
|
||||
"cpuCapacity": {
|
||||
|
||||
@@ -1801,10 +1801,10 @@
|
||||
"filters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"cpuAllocatable": {
|
||||
"type": "string"
|
||||
},
|
||||
"cpuAllocatable": {
|
||||
"cpuArchitecture": {
|
||||
"type": "string"
|
||||
},
|
||||
"cpuCapacity": {
|
||||
|
||||
Reference in New Issue
Block a user