Files
troubleshoot/pkg/analyze/statefulset_status.go
Evans Mungai e156b8c215 chore: Refactor in cluster analysers (#999)
Have all in-cluster analysers implement the same interface. This
will help with the implementation of code that requires making
calls to all analysers

Fixes #995
2023-02-03 15:26:36 +00:00

161 lines
5.2 KiB
Go

package analyzer
import (
"encoding/json"
"fmt"
"path/filepath"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/replicatedhq/troubleshoot/pkg/constants"
appsv1 "k8s.io/api/apps/v1"
)
type AnalyzeStatefulsetStatus struct {
analyzer *troubleshootv1beta2.StatefulsetStatus
}
func (a *AnalyzeStatefulsetStatus) Title() string {
if a.analyzer.CheckName != "" {
return a.analyzer.CheckName
}
if a.analyzer.Name != "" && a.analyzer.Namespace != "" {
return fmt.Sprintf("%s/%s Statefulset Status", a.analyzer.Namespace, a.analyzer.Name)
}
if a.analyzer.Name != "" {
return fmt.Sprintf("%s Statefulset Status", a.analyzer.Name)
}
if a.analyzer.Namespace != "" {
return fmt.Sprintf("%s Statefulset Status", a.analyzer.Namespace)
}
return "Statefulset Status"
}
func (a *AnalyzeStatefulsetStatus) IsExcluded() (bool, error) {
return isExcluded(a.analyzer.Exclude)
}
func (a *AnalyzeStatefulsetStatus) Analyze(getFile getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
results, err := analyzeStatefulsetStatus(a.analyzer, findFiles)
if err != nil {
return nil, err
}
for i := range results {
results[i].Strict = a.analyzer.Strict.BoolOrDefaultFalse()
}
return results, nil
}
func analyzeStatefulsetStatus(analyzer *troubleshootv1beta2.StatefulsetStatus, getFileContents getChildCollectedFileContents) ([]*AnalyzeResult, error) {
if analyzer.Name == "" {
return analyzeAllStatefulsetStatuses(analyzer, getFileContents)
} else {
return analyzeOneStatefulsetStatus(analyzer, getFileContents)
}
}
func analyzeOneStatefulsetStatus(analyzer *troubleshootv1beta2.StatefulsetStatus, getFileContents getChildCollectedFileContents) ([]*AnalyzeResult, error) {
excludeFiles := []string{}
files, err := getFileContents(filepath.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_STATEFULSETS, fmt.Sprintf("%s.json", analyzer.Namespace)), excludeFiles)
if err != nil {
return nil, errors.Wrap(err, "failed to read collected statefulsets from namespace")
}
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")
}
var statefulset *appsv1.StatefulSet
for _, s := range statefulsets.Items {
if s.Name == analyzer.Name {
statefulset = s.DeepCopy()
break
}
}
if statefulset == nil {
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")
}
} else {
result = getDefaultStatefulSetResult(statefulset)
}
}
if result == nil {
return nil, nil
}
return []*AnalyzeResult{result}, nil
}
func analyzeAllStatefulsetStatuses(analyzer *troubleshootv1beta2.StatefulsetStatus, getFileContents getChildCollectedFileContents) ([]*AnalyzeResult, error) {
fileNames := make([]string, 0)
if analyzer.Namespace != "" {
fileNames = append(fileNames, filepath.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_STATEFULSETS, fmt.Sprintf("%s.json", analyzer.Namespace)))
}
for _, ns := range analyzer.Namespaces {
fileNames = append(fileNames, filepath.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_STATEFULSETS, fmt.Sprintf("%s.json", ns)))
}
// no namespace specified, so we need to analyze all statefulsets
if len(fileNames) == 0 {
fileNames = append(fileNames, filepath.Join(constants.CLUSTER_RESOURCES_DIR, constants.CLUSTER_RESOURCES_STATEFULSETS, "*.json"))
}
excludeFiles := []string{}
results := []*AnalyzeResult{}
for _, fileName := range fileNames {
files, err := getFileContents(fileName, excludeFiles)
if err != nil {
return nil, errors.Wrap(err, "failed to read collected statefulsets from namespace")
}
for _, collected := range files {
var statefulsets appsv1.StatefulSetList
if err := json.Unmarshal(collected, &statefulsets); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal statefulset list")
}
for _, statefulset := range statefulsets.Items {
result := getDefaultStatefulSetResult(&statefulset)
if result != nil {
results = append(results, result)
}
}
}
}
return results, nil
}
func getDefaultStatefulSetResult(statefulset *appsv1.StatefulSet) *AnalyzeResult {
if statefulset.Status.Replicas == statefulset.Status.ReadyReplicas {
return nil
}
return &AnalyzeResult{
Title: fmt.Sprintf("%s/%s Statefulset Status", statefulset.Namespace, statefulset.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 %s/%s has %d/%d replicas", statefulset.Namespace, statefulset.Name, statefulset.Status.ReadyReplicas, statefulset.Status.Replicas),
}
}