diff --git a/pkg/analyze/node_resources.go b/pkg/analyze/node_resources.go index f23afa3f..fbae50f0 100644 --- a/pkg/analyze/node_resources.go +++ b/pkg/analyze/node_resources.go @@ -2,8 +2,10 @@ package analyzer import ( "encoding/json" + "fmt" "strconv" "strings" + "regexp" "github.com/pkg/errors" troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1" @@ -46,7 +48,7 @@ func analyzeNodeResources(analyzer *troubleshootv1beta1.NodeResources, getCollec for _, outcome := range analyzer.Outcomes { if outcome.Fail != nil { - isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Fail.When, matchingNodeCount) + isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Fail.When, matchingNodes, len(nodes)) if err != nil { return nil, errors.Wrap(err, "failed to parse when") } @@ -59,7 +61,7 @@ func analyzeNodeResources(analyzer *troubleshootv1beta1.NodeResources, getCollec return result, nil } } else if outcome.Warn != nil { - isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Warn.When, matchingNodeCount) + isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Warn.When, matchingNodes, len(nodes)) if err != nil { return nil, errors.Wrap(err, "failed to parse when") } @@ -72,7 +74,7 @@ func analyzeNodeResources(analyzer *troubleshootv1beta1.NodeResources, getCollec return result, nil } } else if outcome.Pass != nil { - isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Pass.When, matchingNodeCount) + isWhenMatch, err := compareNodeResourceConditionalToActual(outcome.Pass.When, matchingNodes, len(nodes)) if err != nil { return nil, errors.Wrap(err, "failed to parse when") } @@ -90,39 +92,60 @@ func analyzeNodeResources(analyzer *troubleshootv1beta1.NodeResources, getCollec return result, nil } -func compareNodeResourceConditionalToActual(conditional string, actual int) (bool, error) { +func compareNodeResourceConditionalToActual(conditional string, matchingNodes []corev1.Node, totalNodeCount int) (bool, error) { if conditional == "" { return true, nil } parts := strings.Split(strings.TrimSpace(conditional), " ") - if len(parts) != 2 { + if len(parts) == 2 { + parts = append([]string{"count"}, parts...) + } + + if len(parts) != 3 { return false, errors.New("unable to parse nodeResources conditional") } - operator := parts[0] - desiredValue, err := strconv.Atoi(parts[1]) + operator := parts[1] + var desiredValue interface{} + desiredValue = parts[2] + + parsedDesiredValue, err := strconv.Atoi(parts[2]) if err != nil { - return false, errors.Wrap(err, "failed to parse nodeResource value") + desiredValue = parsedDesiredValue } - switch operator { - case "=", "==", "===": - return desiredValue == actual, nil - case "<": - return actual < desiredValue, nil - case "<=": - return actual <= desiredValue, nil - case ">": - return actual > desiredValue, nil - case ">=": - return actual >= desiredValue, nil - } + var actualValue interface{} + actualValue = len(matchingNodes) + + reg := regexp.MustCompile("(?P.*)\((?P.*)\)") + match := reg.FindStringSubmatch(parts[0]) + + fmt.Printf("reg = %#v\n", reg) + // result := make(map[string]string) + + + // switch operator { + // case "=", "==", "===": + // return desiredValue == actualValue, nil + // case "<": + // return actualValue < desiredValue, nil + // case "<=": + // return actualValue <= desiredValue, nil + // case ">": + // return actualValue > desiredValue, nil + // case ">=": + // return actualValue >= desiredValue, nil + // } return false, errors.New("unexpected conditional in nodeResources") } +func findMin(nodes []codev1.Node, property string) (string, error) { + return "", errors.New("not implemented") +} + func nodeMatchesFilters(node corev1.Node, filters *troubleshootv1beta1.NodeResourceFilters) (bool, error) { if filters == nil { return true, nil diff --git a/pkg/analyze/node_resources_test.go b/pkg/analyze/node_resources_test.go index 9353c271..d74fdf27 100644 --- a/pkg/analyze/node_resources_test.go +++ b/pkg/analyze/node_resources_test.go @@ -12,40 +12,60 @@ import ( func Test_compareNodeResourceConditionalToActual(t *testing.T) { tests := []struct { - name string - conditional string - actual int - expected bool + name string + conditional string + matchingNodeCount int + totalNodeCount int + expected bool }{ { - name: "=", - conditional: "= 5", - actual: 5, - expected: true, + name: "=", + conditional: "= 5", + matchingNodeCount: 5, + totalNodeCount: 1, + expected: true, }, { - name: "<= (pass)", - conditional: "<= 5", - actual: 4, - expected: true, + name: "<= (pass)", + conditional: "<= 5", + matchingNodeCount: 4, + totalNodeCount: 1, + expected: true, }, { - name: "<= (fail)", - conditional: "<= 5", - actual: 6, - expected: false, + name: "<= (fail)", + conditional: "<= 5", + matchingNodeCount: 6, + totalNodeCount: 1, + expected: false, }, { - name: "> (pass)", - conditional: "> 5", - actual: 6, - expected: true, + name: "> (pass)", + conditional: "> 5", + matchingNodeCount: 6, + totalNodeCount: 1, + expected: true, }, { - name: ">=(fail)", - conditional: ">= 5", - actual: 4, - expected: false, + name: ">= (fail)", + conditional: ">= 5", + matchingNodeCount: 4, + totalNodeCount: 1, + expected: false, + }, + { + name: "min(memoryCapacity) <= 16Gi (pass)", + conditional: "min(memoryCapacity) <= 16Gi", + matchingNodeCount: 2, + totalNodeCount: 2, + expected: true, + }, + { + name: "min(memoryCapacity) <= 16Gi", + conditional: "min(memoryCapacity) <= 16Gi", + matchingNodeCount: 1, + totalNodeCount: 2, + expected: false, }, } @@ -53,7 +73,7 @@ func Test_compareNodeResourceConditionalToActual(t *testing.T) { t.Run(test.name, func(t *testing.T) { req := require.New(t) - actual, err := compareNodeResourceConditionalToActual(test.conditional, test.actual) + actual, err := compareNodeResourceConditionalToActual(test.conditional, test.matchingNodeCount, test.totalNodeCount) req.NoError(err) assert.Equal(t, test.expected, actual)