Skip to content

Commit

Permalink
we can afford an extra (now) deprecated Restic repository type
Browse files Browse the repository at this point in the history
..better than using unstructured and be the deer in headlights

Signed-off-by: Archit Sharma <[email protected]>
  • Loading branch information
arcolife committed Nov 3, 2023
1 parent a49cb3a commit 278f23d
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 25 deletions.
62 changes: 62 additions & 0 deletions pkg/analyze/types/restic_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package analyzer

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ResticRepositorySpec is the specification for a ResticRepository.
type ResticRepositorySpec struct {
// VolumeNamespace is the namespace this restic repository contains
// pod volume backups for.
VolumeNamespace string `json:"volumeNamespace"`

// BackupStorageLocation is the name of the BackupStorageLocation
// that should contain this repository.
BackupStorageLocation string `json:"backupStorageLocation"`

// ResticIdentifier is the full restic-compatible string for identifying
// this repository.
ResticIdentifier string `json:"resticIdentifier"`

// MaintenanceFrequency is how often maintenance should be run.
MaintenanceFrequency metav1.Duration `json:"maintenanceFrequency"`
}

// ResticRepositoryPhase represents the lifecycle phase of a ResticRepository.
// +kubebuilder:validation:Enum=New;Ready;NotReady
type ResticRepositoryPhase string

const (
ResticRepositoryPhaseNew ResticRepositoryPhase = "New"
ResticRepositoryPhaseReady ResticRepositoryPhase = "Ready"
ResticRepositoryPhaseNotReady ResticRepositoryPhase = "NotReady"
)

// ResticRepositoryStatus is the current status of a ResticRepository.
type ResticRepositoryStatus struct {
// Phase is the current state of the ResticRepository.
// +optional
Phase ResticRepositoryPhase `json:"phase,omitempty"`

// Message is a message about the current status of the ResticRepository.
// +optional
Message string `json:"message,omitempty"`

// LastMaintenanceTime is the last time maintenance was run.
// +optional
// +nullable
LastMaintenanceTime *metav1.Time `json:"lastMaintenanceTime,omitempty"`
}

type ResticRepository struct {
metav1.TypeMeta `json:",inline"`

// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`

// +optional
Spec ResticRepositorySpec `json:"spec,omitempty"`

// +optional
Status ResticRepositoryStatus `json:"status,omitempty"`
}
67 changes: 50 additions & 17 deletions pkg/analyze/velero.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ import (
"path/filepath"
"strings"

restic_types "github.com/replicatedhq/troubleshoot/pkg/analyze/types"

"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

const (
DefaultVeleroNamespace = "velero"
)

type AnalyzeVelero struct {
Expand Down Expand Up @@ -45,11 +42,6 @@ func (a *AnalyzeVelero) Analyze(getFile getCollectedFileContents, findFiles getC
}

func (a *AnalyzeVelero) veleroStatus(analyzer *troubleshootv1beta2.VeleroAnalyze, getFileContents getCollectedFileContents, findFiles getChildCollectedFileContents) ([]*AnalyzeResult, error) {
ns := DefaultVeleroNamespace
if analyzer.Namespace != "" {
ns = analyzer.Namespace
}

excludeFiles := []string{}

// get backuprepositories.velero.io
Expand Down Expand Up @@ -77,12 +69,14 @@ func (a *AnalyzeVelero) veleroStatus(analyzer *troubleshootv1beta2.VeleroAnalyze
if err != nil {
return nil, errors.Wrapf(err, "failed to find velero restic repositories files under %s", resticRepositoriesDir)
}
resticRepositories := []unstructured.Unstructured{}
resticRepositories := []*restic_types.ResticRepository{}
for key, resticRepositoryJson := range resticRepositoriesJson {
var resticRepositoryArray []*restic_types.ResticRepository
err := json.Unmarshal(resticRepositoryJson, &resticRepositories)
if err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal restic repository json from %s", key)
}
resticRepositories = append(resticRepositories, resticRepositoryArray...)
}

// get backups.velero.io
Expand Down Expand Up @@ -241,7 +235,7 @@ func (a *AnalyzeVelero) veleroStatus(analyzer *troubleshootv1beta2.VeleroAnalyze
volumeSnapshotLocations = append(volumeSnapshotLocations, volumeSnapshotLocationArray...)
}

logsDir := GetVeleroLogsDirectory(ns)
logsDir := GetVeleroLogsDirectory()
logsGlob := filepath.Join(logsDir, "node-agent*", "*.log")
logs, err := findFiles(logsGlob, excludeFiles)

Expand All @@ -252,6 +246,7 @@ func (a *AnalyzeVelero) veleroStatus(analyzer *troubleshootv1beta2.VeleroAnalyze
results := []*AnalyzeResult{}
results = append(results, analyzeLogs(logs)...)
results = append(results, analyzeBackupRepositories(backupRepositories)...)
results = append(results, analyzeResticRepositories(resticRepositories)...)
results = append(results, analyzeBackups(backups)...)
results = append(results, analyzeBackupStorageLocations(backupStorageLocations)...)
results = append(results, analyzeDeleteBackupRequests(deleteBackupRequests)...)
Expand All @@ -268,7 +263,7 @@ func analyzeBackupRepositories(backupRepositories []*velerov1.BackupRepository)
results := []*AnalyzeResult{}
readyCount := 0
backupRepositoriesResult := &AnalyzeResult{
Title: "At least 1 Velero Backup Repository configured",
Title: "At least 1 Backup Repository configured",
}
if len(backupRepositories) == 0 {
backupRepositoriesResult.IsFail = true
Expand All @@ -295,11 +290,49 @@ func analyzeBackupRepositories(backupRepositories []*velerov1.BackupRepository)
}
}
results = append(results, backupRepositoriesResult)

return results

}

func analyzeResticRepositories(resticRepositories []*restic_types.ResticRepository) []*AnalyzeResult {
results := []*AnalyzeResult{}
readyCount := 0
resticRepositoriesResult := &AnalyzeResult{
Title: "At least 1 Restic Repository configured",
}
if len(resticRepositories) == 0 {
resticRepositoriesResult.IsFail = true
resticRepositoriesResult.Message = "No restic repositories configured"
} else {
for _, resticRepository := range resticRepositories {
// phase, _, err := unstructured.NestedString(resticRepository.Object, "status", "phase")
// if err != nil {
// klog.V(2).Infof("Failed to get phase for restic repository %s: %v", resticRepository.GetName(), err)
// }
// if phase != "Ready" {
if resticRepository.Status.Phase != restic_types.ResticRepositoryPhaseReady {
result := &AnalyzeResult{
Title: fmt.Sprintf("Restic Repository %s", resticRepository.GetName()),
}
result.Message = fmt.Sprintf("Restic Repository [%s] is in phase %s", resticRepository.Name, resticRepository.Status.Phase)
result.IsWarn = true
results = append(results, result)
} else {
readyCount++
}
}
if readyCount > 0 {
resticRepositoriesResult.IsPass = true
resticRepositoriesResult.Message = fmt.Sprintf("Found %d restic repositories configured and %d Ready", len(resticRepositories), readyCount)
} else {
resticRepositoriesResult.IsWarn = true
resticRepositoriesResult.Message = fmt.Sprintf("Found %d configured restic repositories, but none are ready", len(resticRepositories))
}
}
results = append(results, resticRepositoriesResult)
return results
}

func analyzeBackups(backups []*velerov1.Backup) []*AnalyzeResult {
results := []*AnalyzeResult{}

Expand Down Expand Up @@ -337,7 +370,7 @@ func analyzeBackupStorageLocations(backupStorageLocations []*velerov1.BackupStor
results := []*AnalyzeResult{}
availableCount := 0
bslResult := &AnalyzeResult{
Title: "At least 1 Velero Backup Storage Location configured",
Title: "At least 1 Backup Storage Location configured",
}

if len(backupStorageLocations) == 0 {
Expand Down Expand Up @@ -615,8 +648,8 @@ func GetVeleroDownloadRequestsDirectory() string {
return "cluster-resources/custom-resources/downloadrequests.velero.io"
}

func GetVeleroLogsDirectory(namespace string) string {
return fmt.Sprint("%s/logs", namespace)
func GetVeleroLogsDirectory() string {
return "velero/logs"
}

func GetVeleroPodVolumeBackupsDirectory() string {
Expand Down
74 changes: 67 additions & 7 deletions pkg/analyze/velero_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

restic_types "github.com/replicatedhq/troubleshoot/pkg/analyze/types"
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -27,7 +28,7 @@ func TestAnalyzeVelero_BackupRepositories(t *testing.T) {
},
want: []*AnalyzeResult{
{
Title: "At least 1 Velero Backup Repository configured",
Title: "At least 1 Backup Repository configured",
Message: "No backup repositories configured",
IsFail: true,
},
Expand All @@ -50,7 +51,7 @@ func TestAnalyzeVelero_BackupRepositories(t *testing.T) {
},
want: []*AnalyzeResult{
{
Title: "At least 1 Velero Backup Repository configured",
Title: "At least 1 Backup Repository configured",
Message: "Found 1 backup repositories configured and 1 Ready",
IsPass: true,
},
Expand Down Expand Up @@ -95,7 +96,7 @@ func TestAnalyzeVelero_BackupRepositories(t *testing.T) {
IsWarn: true,
},
{
Title: "At least 1 Velero Backup Repository configured",
Title: "At least 1 Backup Repository configured",
Message: "Found 2 backup repositories configured and 1 Ready",
IsPass: true,
},
Expand Down Expand Up @@ -127,7 +128,7 @@ func TestAnalyzeVelero_BackupRepositories(t *testing.T) {
IsWarn: true,
},
{
Title: "At least 1 Velero Backup Repository configured",
Title: "At least 1 Backup Repository configured",
Message: "Found 1 configured backup repositories, but none are ready",
IsWarn: true,
},
Expand All @@ -143,6 +144,65 @@ func TestAnalyzeVelero_BackupRepositories(t *testing.T) {
}
}

func TestAnalyzeVelero_ResticRepositories(t *testing.T) {
type args struct {
resticRepositories []*restic_types.ResticRepository
}
tests := []struct {
name string
args args
want []*AnalyzeResult
}{
{
name: "no restic repositories",
args: args{
resticRepositories: []*restic_types.ResticRepository{},
},
want: []*AnalyzeResult{
{
Title: "At least 1 Restic Repository configured",
Message: "No restic repositories configured",
IsFail: true,
},
},
},
{
name: "1 restic repository and 1 Ready",
args: args{
resticRepositories: []*restic_types.ResticRepository{
{
ObjectMeta: metav1.ObjectMeta{
Name: "default-default-restic-245sd",
Namespace: "velero",
},
Spec: restic_types.ResticRepositorySpec{
BackupStorageLocation: "default",
VolumeNamespace: "velero",
},
Status: restic_types.ResticRepositoryStatus{
Phase: restic_types.ResticRepositoryPhaseReady,
},
},
},
},
want: []*AnalyzeResult{
{
Title: "At least 1 Restic Repository configured",
Message: "Found 1 restic repositories configured and 1 Ready",
IsPass: true,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := analyzeResticRepositories(tt.args.resticRepositories); !reflect.DeepEqual(got, tt.want) {
t.Errorf("analyzeResticRepositories() = %v, want %v", got, tt.want)
}
})
}
}

func TestAnalyzeVelero_Backups(t *testing.T) {
type args struct {
backups []*velerov1.Backup
Expand Down Expand Up @@ -242,7 +302,7 @@ func TestAnalyzeVelero_BackupStorageLocations(t *testing.T) {
},
want: []*AnalyzeResult{
{
Title: "At least 1 Velero Backup Storage Location configured",
Title: "At least 1 Backup Storage Location configured",
Message: "No backup storage locations configured",
IsFail: true,
},
Expand All @@ -268,7 +328,7 @@ func TestAnalyzeVelero_BackupStorageLocations(t *testing.T) {
},
want: []*AnalyzeResult{
{
Title: "At least 1 Velero Backup Storage Location configured",
Title: "At least 1 Backup Storage Location configured",
Message: "Found 1 backup storage locations configured and 1 Available",
IsPass: true,
},
Expand Down Expand Up @@ -299,7 +359,7 @@ func TestAnalyzeVelero_BackupStorageLocations(t *testing.T) {
IsWarn: true,
},
{
Title: "At least 1 Velero Backup Storage Location configured",
Title: "At least 1 Backup Storage Location configured",
Message: "Found 1 configured backup storage locations, but none are available",
IsWarn: true,
},
Expand Down
4 changes: 3 additions & 1 deletion pkg/types/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package types

import "fmt"
import (
"fmt"
)

type NotFoundError struct {
Name string
Expand Down

0 comments on commit 278f23d

Please sign in to comment.