Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions cmd/clean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package cmd

import (
"fmt"
"os"

"github.com/andreclaro/ssm/internal/storage"
"github.com/spf13/cobra"
)

// cleanCmd represents the clean command
var cleanCmd = &cobra.Command{
Use: "clean",
Short: "Remove instances with ConnectionLost state from the database",
Long: `Remove all instances from the database where the state is 'ConnectionLost'.

This command is useful for cleaning up instances that have lost their connection
and are no longer accessible.

Examples:
ssm clean # Remove all instances with ConnectionLost state`,
Run: runClean,
}

func init() {
rootCmd.AddCommand(cleanCmd)
}

func runClean(cmd *cobra.Command, args []string) {
// Initialize database
if err := storage.InitDB(); err != nil {
fmt.Fprintf(os.Stderr, "Failed to initialize database: %v\n", err)
os.Exit(1)
}

// Create repository
repo := storage.NewInstanceRepository()

// Delete instances with ConnectionLost state
count, err := repo.DeleteByState("ConnectionLost")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to clean instances: %v\n", err)
os.Exit(1)
}

fmt.Printf("Removed %d instance(s) from database\n", count)
}
31 changes: 31 additions & 0 deletions internal/storage/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,37 @@ func (r *InstanceRepository) DeleteStale(olderThan time.Duration) error {
return nil
}

// DeleteByState removes instances with the specified state
func (r *InstanceRepository) DeleteByState(state string) (int64, error) {
// First, get the instance IDs that will be deleted to clean up associated tags
var instanceIDs []string
if err := DB.Model(&Instance{}).Where("state = ?", state).Pluck("instance_id", &instanceIDs).Error; err != nil {
return 0, fmt.Errorf("failed to find instances with state %s: %w", state, err)
}

// Delete associated tags
if len(instanceIDs) > 0 {
if err := DB.Where("instance_id IN ?", instanceIDs).Delete(&Tag{}).Error; err != nil {
return 0, fmt.Errorf("failed to delete tags for instances with state %s: %w", state, err)
}
}

// Delete instances
result := DB.Where("state = ?", state).Delete(&Instance{})
if result.Error != nil {
return 0, fmt.Errorf("failed to delete instances with state %s: %w", state, result.Error)
}

if result.RowsAffected > 0 {
logrus.WithFields(logrus.Fields{
"count": result.RowsAffected,
"state": state,
}).Info("Deleted instances by state")
}

return result.RowsAffected, nil
}

// GetStats returns statistics about stored instances
func (r *InstanceRepository) GetStats() (map[string]int, error) {
stats := make(map[string]int)
Expand Down