diff --git a/pkg/analyze/longhorn.go b/pkg/analyze/longhorn.go index 8da7c64f..f08a3c18 100644 --- a/pkg/analyze/longhorn.go +++ b/pkg/analyze/longhorn.go @@ -1,14 +1,18 @@ package analyzer import ( + "bufio" + "bytes" "fmt" "path/filepath" + "strings" longhornv1beta1 "github.com/longhorn/longhorn-manager/k8s/pkg/apis/longhorn/v1beta1" longhorntypes "github.com/longhorn/longhorn-manager/types" "github.com/pkg/errors" troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2" "github.com/replicatedhq/troubleshoot/pkg/collect" + "github.com/replicatedhq/troubleshoot/pkg/redact" "gopkg.in/yaml.v2" ) @@ -17,14 +21,17 @@ func longhorn(analyzer *troubleshootv1beta2.LonghornAnalyze, getCollectedFileCon if analyzer.Namespace != "" { ns = analyzer.Namespace } + + // get nodes.longhorn.io nodesDir := collect.GetLonghornNodesDirectory(ns) - glob := filepath.Join(nodesDir, "*") - nodesYaml, err := findFiles(glob) + nodesGlob := filepath.Join(nodesDir, "*") + nodesYaml, err := findFiles(nodesGlob) if err != nil { return nil, errors.Wrapf(err, "failed to find longhorn nodes files under %s", nodesDir) } nodes := []*longhornv1beta1.Node{} for key, nodeYaml := range nodesYaml { + nodeYaml = stripRedactedLines(nodeYaml) node := &longhornv1beta1.Node{} err := yaml.Unmarshal(nodeYaml, node) if err != nil { @@ -33,12 +40,34 @@ func longhorn(analyzer *troubleshootv1beta2.LonghornAnalyze, getCollectedFileCon nodes = append(nodes, node) } + // get replicas.longhorn.io + replicasDir := collect.GetLonghornReplicasDirectory(ns) + replicasGlob := filepath.Join(replicasDir, "*") + replicasYaml, err := findFiles(replicasGlob) + if err != nil { + return nil, errors.Wrapf(err, "failed to find longhorn replicas files under %s", replicasDir) + } + replicas := []*longhornv1beta1.Replica{} + for key, replicaYaml := range replicasYaml { + replicaYaml = stripRedactedLines(replicaYaml) + replica := &longhornv1beta1.Replica{} + err := yaml.Unmarshal(replicaYaml, replica) + if err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal replica yaml from %s", key) + } + replicas = append(replicas, replica) + } + results := []*AnalyzeResult{} for _, node := range nodes { results = append(results, analyzeLonghornNodeSchedulable(node)) } + for _, replica := range replicas { + results = append(results, analyzeLonghornReplica(replica)) + } + return results, nil } @@ -67,3 +96,46 @@ func analyzeLonghornNodeSchedulable(node *longhornv1beta1.Node) *AnalyzeResult { return result } + +func analyzeLonghornReplica(replica *longhornv1beta1.Replica) *AnalyzeResult { + result := &AnalyzeResult{ + Title: fmt.Sprintf("Longhorn Replica: %s", replica.Name), + } + + if replica.Spec.FailedAt != "" { + result.IsWarn = true + result.Message = fmt.Sprintf("Longhorn replica %s failed at %s", replica.Name, replica.Spec.FailedAt) + return result + } + + desired := replica.Spec.InstanceSpec.DesireState + actual := replica.Status.InstanceStatus.CurrentState + + if desired != actual { + result.IsWarn = true + result.Message = fmt.Sprintf("Longhorn replica %s current status %q, should be %q", replica.Name, actual, desired) + return result + } + + result.IsPass = true + result.Message = fmt.Sprintf("Replica is %s", actual) + + return result +} + +func stripRedactedLines(yaml []byte) []byte { + buf := bytes.NewBuffer(yaml) + scanner := bufio.NewScanner(buf) + + out := []byte{} + + for scanner.Scan() { + if strings.Contains(scanner.Text(), redact.MASK_TEXT) { + continue + } + out = append(out, scanner.Bytes()...) + out = append(out, '\n') + } + + return out +} diff --git a/pkg/analyze/longhorn_test.go b/pkg/analyze/longhorn_test.go index b378cf49..7c38f4f0 100644 --- a/pkg/analyze/longhorn_test.go +++ b/pkg/analyze/longhorn_test.go @@ -64,3 +64,81 @@ func TestAnalyzeLonghornNodeSchedulable(t *testing.T) { }) } } + +func TestAnalyzeLonghornReplica(t *testing.T) { + tests := []struct { + name string + replica *longhornv1beta1.Replica + expect *AnalyzeResult + }{ + { + name: "running", + replica: &longhornv1beta1.Replica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-uuid-1", + }, + Spec: longhorntypes.ReplicaSpec{ + InstanceSpec: longhorntypes.InstanceSpec{ + DesireState: longhorntypes.InstanceStateRunning, + }, + }, + Status: longhorntypes.ReplicaStatus{ + InstanceStatus: longhorntypes.InstanceStatus{ + CurrentState: longhorntypes.InstanceStateRunning, + }, + }, + }, + expect: &AnalyzeResult{ + Title: "Longhorn Replica: pvc-uuid-1", + IsPass: true, + Message: "Replica is running", + }, + }, + { + name: "stopped", + replica: &longhornv1beta1.Replica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-uuid-1", + }, + Spec: longhorntypes.ReplicaSpec{ + InstanceSpec: longhorntypes.InstanceSpec{ + DesireState: longhorntypes.InstanceStateRunning, + }, + }, + Status: longhorntypes.ReplicaStatus{ + InstanceStatus: longhorntypes.InstanceStatus{ + CurrentState: longhorntypes.InstanceStateStopped, + }, + }, + }, + expect: &AnalyzeResult{ + Title: "Longhorn Replica: pvc-uuid-1", + IsWarn: true, + Message: `Longhorn replica pvc-uuid-1 current status "stopped", should be "running"`, + }, + }, + { + name: "failed", + replica: &longhornv1beta1.Replica{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc-uuid-1", + }, + Spec: longhorntypes.ReplicaSpec{ + FailedAt: "20210527T19:43:35", + }, + }, + expect: &AnalyzeResult{ + Title: "Longhorn Replica: pvc-uuid-1", + IsWarn: true, + Message: "Longhorn replica pvc-uuid-1 failed at 20210527T19:43:35", + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := analyzeLonghornReplica(test.replica) + + assert.Equal(t, test.expect, got) + }) + } +} diff --git a/pkg/client/troubleshootclientset/fake/register.go b/pkg/client/troubleshootclientset/fake/register.go index 8010c884..89d94f58 100644 --- a/pkg/client/troubleshootclientset/fake/register.go +++ b/pkg/client/troubleshootclientset/fake/register.go @@ -29,7 +29,7 @@ import ( var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) -var parameterCodec = runtime.NewParameterCodec(scheme) + var localSchemeBuilder = runtime.SchemeBuilder{ troubleshootv1beta1.AddToScheme, troubleshootv1beta2.AddToScheme,