This commit is contained in:
@@ -398,3 +398,107 @@ func parseSize(s string) (uint64, error) {
|
||||
|
||||
return val * multiplier, nil
|
||||
}
|
||||
|
||||
// ListSnapshots returns all snapshots for a dataset (or all if dataset is empty)
|
||||
func (s *Service) ListSnapshots(dataset string) ([]models.Snapshot, error) {
|
||||
args := []string{"list", "-H", "-o", "name,used,creation", "-t", "snapshot", "-s", "creation"}
|
||||
if dataset != "" {
|
||||
args = append(args, "-r", dataset)
|
||||
} else {
|
||||
args = append(args, "-r")
|
||||
}
|
||||
|
||||
output, err := s.execCommand(s.zfsPath, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var snapshots []models.Snapshot
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
fullName := fields[0]
|
||||
// Snapshot name format: dataset@snapshot
|
||||
parts := strings.Split(fullName, "@")
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
datasetName := parts[0]
|
||||
|
||||
snapshot := models.Snapshot{
|
||||
Name: fullName,
|
||||
Dataset: datasetName,
|
||||
}
|
||||
|
||||
// Parse size
|
||||
if used, err := parseSize(fields[1]); err == nil {
|
||||
snapshot.Size = used
|
||||
}
|
||||
|
||||
// Parse creation time
|
||||
// ZFS creation format: "Mon Jan 2 15:04:05 2006"
|
||||
createdStr := strings.Join(fields[2:], " ")
|
||||
if t, err := time.Parse("Mon Jan 2 15:04:05 2006", createdStr); err == nil {
|
||||
snapshot.CreatedAt = t
|
||||
} else {
|
||||
// Try RFC3339 format if available
|
||||
if t, err := time.Parse(time.RFC3339, createdStr); err == nil {
|
||||
snapshot.CreatedAt = t
|
||||
}
|
||||
}
|
||||
|
||||
snapshots = append(snapshots, snapshot)
|
||||
}
|
||||
|
||||
return snapshots, nil
|
||||
}
|
||||
|
||||
// CreateSnapshot creates a new snapshot
|
||||
func (s *Service) CreateSnapshot(dataset, name string, recursive bool) error {
|
||||
args := []string{"snapshot"}
|
||||
if recursive {
|
||||
args = append(args, "-r")
|
||||
}
|
||||
|
||||
snapshotName := fmt.Sprintf("%s@%s", dataset, name)
|
||||
args = append(args, snapshotName)
|
||||
|
||||
_, err := s.execCommand(s.zfsPath, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// DestroySnapshot destroys a snapshot
|
||||
func (s *Service) DestroySnapshot(name string, recursive bool) error {
|
||||
args := []string{"destroy"}
|
||||
if recursive {
|
||||
args = append(args, "-r")
|
||||
}
|
||||
args = append(args, name)
|
||||
_, err := s.execCommand(s.zfsPath, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetSnapshot returns snapshot details
|
||||
func (s *Service) GetSnapshot(name string) (*models.Snapshot, error) {
|
||||
snapshots, err := s.ListSnapshots("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, snap := range snapshots {
|
||||
if snap.Name == name {
|
||||
return &snap, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("snapshot %s not found", name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user