Files
troubleshoot/pkg/preflight/validate_specs.go

154 lines
5.2 KiB
Go

package preflight
import (
"reflect"
"github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/loader"
"github.com/replicatedhq/troubleshoot/pkg/multitype"
"github.com/replicatedhq/troubleshoot/pkg/types"
)
// validatePreflight validates the preflight spec and returns a warning if there is any
func validatePreflight(kinds *loader.TroubleshootKinds) *types.ExitCodeWarning {
if len(kinds.PreflightsV1Beta2) == 0 && len(kinds.HostPreflightsV1Beta2) == 0 {
return types.NewExitCodeWarning("no preflight or host preflight spec was found")
}
for _, spec := range kinds.PreflightsV1Beta2 {
warning := validatePreflightSpecItems(spec.Spec.Collectors, spec.Spec.Analyzers)
if warning != nil {
return warning
}
}
for _, spec := range kinds.HostPreflightsV1Beta2 {
warning := validateHostPreflightSpecItems(spec.Spec.Collectors, spec.Spec.Analyzers)
if warning != nil {
return warning
}
}
return nil
}
// validatePreflightSpecItems validates the preflight spec items and returns a warning if there are any
// clusterResources or clusterInfo collectors added automatically to the preflight spec. It cannot be excluded
func validatePreflightSpecItems(collectors []*v1beta2.Collect, analyzers []*v1beta2.Analyze) *types.ExitCodeWarning {
var numberOfExcludedCollectors, numberOfExcludedAnalyzers int
var numberOfExcludedDefaultCollectors int
numberOfCollectors := len(collectors) + 2
numberOfAnalyzers := len(analyzers)
if numberOfCollectors >= 0 {
collectorsInterface := make([]interface{}, len(collectors))
for i, v := range collectors {
if v.ClusterInfo != nil || v.ClusterResources != nil {
numberOfExcludedDefaultCollectors++
}
collectorsInterface[i] = v
}
numberOfExcludedCollectors += countExcludedItems(collectorsInterface)
if numberOfExcludedCollectors+numberOfExcludedDefaultCollectors == numberOfCollectors {
return types.NewExitCodeWarning("All collectors were excluded by the applied values")
}
}
// if there are no analyzers, return a warning
// else check if all analyzers are excluded
if numberOfAnalyzers == 0 {
return types.NewExitCodeWarning("No analyzers found")
} else {
analyzersInterface := make([]interface{}, len(analyzers))
for i, v := range analyzers {
analyzersInterface[i] = v
}
numberOfExcludedAnalyzers = countExcludedItems(analyzersInterface)
if numberOfExcludedAnalyzers == numberOfAnalyzers {
return types.NewExitCodeWarning("All analyzers were excluded by the applied values")
}
}
return nil
}
// validateHostPreflightSpecItems validates the host preflight spec items and returns a warning if there is any
// no collectors are added or excluded automatically to the host preflight spec
func validateHostPreflightSpecItems(collectors []*v1beta2.HostCollect, analyzers []*v1beta2.HostAnalyze) *types.ExitCodeWarning {
var numberOfExcludedCollectors, numberOfExcludedAnalyzers int
numberOfCollectors := len(collectors)
numberOfAnalyzers := len(analyzers)
// if there are no collectors, return a warning
if numberOfCollectors == 0 {
return types.NewExitCodeWarning("No collectors found")
}
// if there are no analyzers, return a warning
if numberOfAnalyzers == 0 {
return types.NewExitCodeWarning("No analyzers found")
}
collectorsInterface := make([]interface{}, len(collectors))
for i, v := range collectors {
collectorsInterface[i] = v
}
analyzersInterface := make([]interface{}, len(analyzers))
for i, v := range analyzers {
analyzersInterface[i] = v
}
numberOfExcludedCollectors = countExcludedItems(collectorsInterface)
numberOfExcludedAnalyzers = countExcludedItems(analyzersInterface)
if numberOfExcludedCollectors == numberOfCollectors {
return types.NewExitCodeWarning("All collectors were excluded by the applied values")
}
if numberOfExcludedAnalyzers == numberOfAnalyzers {
return types.NewExitCodeWarning("All analyzers were excluded by the applied values")
}
return nil
}
// countExcludedItems counts and returns the number of excluded items in the given items slice.
// Items are assumed to be structures that may have an "Exclude" field as bool
// If the "Exclude" field is true, the item is considered excluded.
func countExcludedItems(items []interface{}) int {
numberOfExcludedItems := 0
for _, item := range items {
itemElem := reflect.ValueOf(item).Elem()
// Loop over all fields of the current item.
for i := 0; i < itemElem.NumField(); i++ {
// Get the value of the current field.
itemValue := itemElem.Field(i)
// If the current field is a pointer to a struct, check if it has an "Exclude" field.
if !itemValue.IsNil() {
elem := itemValue.Elem()
if elem.Kind() == reflect.Struct {
// Look for a field named "Exclude" in the struct.
excludeField := elem.FieldByName("Exclude")
if excludeField.IsValid() {
// Try to get the field's value as a *multitype.BoolOrString.
excludeValue, ok := excludeField.Interface().(*multitype.BoolOrString)
// If the field's value was successfully obtained and is not nil, and the value is true
if ok && excludeValue != nil {
if excludeValue.BoolOrDefaultFalse() {
numberOfExcludedItems++
}
}
}
}
}
}
}
return numberOfExcludedItems
}