package cmd import ( "fmt" "time" "regexp" "strings" ) /******************************************************************************** * List all snapshots jails have *******************************************************************************/ func ListJailsSnapshots(args []string) { var jailNames []string var snapshots []Snapshot if len(args) > 0 { for _, a := range args { jailNames = append(jailNames, a) } } if len(jailNames) == 0 || len(args) == 0 { for _, j := range gJails { snapshots = append(snapshots, listJailSnapshots(j)...) } } else { for _, cj := range gJails { for _, jn := range jailNames { if strings.EqualFold(cj.Name, jn) { snapshots = append(snapshots, listJailSnapshots(cj)...) } } } } displaySnapshotsFields(snapshots, []string{"Jailname","Name","Creation","Referenced","Used"}) } /******************************************************************************** * List all snapshots a jail have *******************************************************************************/ func listJailSnapshots(jail Jail) []Snapshot { var snapshots []Snapshot // 1. List all datasets // TODO : Include mounted filesystems? rs := strings.Split(jail.RootPath, "/") rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/")) cmd := fmt.Sprintf("zfs list -r -H -o name,mountpoint,used,referenced,creation -t snapshot %s", rootDataset) out, err := executeCommand(cmd) if err != nil { fmt.Printf("Error: %s\n", err.Error()) return snapshots } dateLayout := "Mon Jan _2 15:04 2006" loc, _ := time.LoadLocation(gTimeZone) for _, line := range strings.Split(out, "\n") { if len(line) > 0 { ls := strings.Split(line, "\t") // Parse creation date so we can use it to sort snapshots creationts, err := time.ParseInLocation(dateLayout, ls[4], loc) if err != nil { fmt.Println("Error while parsing date %s:", ls[4], err) return snapshots } // Get subdir to append to snapshot name subdir := strings.Replace(strings.Split(ls[0], "@")[0], rootDataset, "", 1) snapshots = append(snapshots, Snapshot{Dsname: ls[0], Name: fmt.Sprintf("%s%s", strings.Split(ls[0], "@")[1], subdir), Jailname: jail.Name, Mountpoint: ls[1], Used: ls[2], Referenced: ls[3], Creation: creationts}) } } // Sort snapshots by creation date ss := initSnapshotSortStruct() SnapshotsOrderedBy(ss.CreationInc).Sort(snapshots) return snapshots } /******************************************************************************** * Create snapshot for jail(s) *******************************************************************************/ func CreateJailSnapshot(args []string) { var jailNames []string if len(args) > 0 { for _, a := range args { jailNames = append(jailNames, a) } } for _, cj := range gJails { for _, jn := range jailNames { if strings.EqualFold(cj.Name, jn) { createJailSnapshot(cj) } } } } /******************************************************************************** * Create snapshot for a jail *******************************************************************************/ func createJailSnapshot(jail Jail) error { rs := strings.Split(jail.RootPath, "/") rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/")) cmd := fmt.Sprintf("zfs snapshot -r %s@%s", rootDataset, gSnapshotName) _, err := executeCommand(cmd) if err != nil { fmt.Printf("Error creating snapshot %s@%s: %s\n", rootDataset, gSnapshotName, err.Error()) return err } fmt.Printf("Snapshot %s@%s created\n", rootDataset, gSnapshotName) return nil } /******************************************************************************** * Delete snapshot for jail(s) *******************************************************************************/ func DeleteJailSnapshot(args []string) { var jailNames []string if len(args) > 0 { for _, a := range args { jailNames = append(jailNames, a) } } for _, cj := range gJails { for _, jn := range jailNames { if strings.EqualFold(cj.Name, jn) { deleteJailSnapshot(cj) } } } } /******************************************************************************** * Delete snapshot for a jail *******************************************************************************/ func deleteJailSnapshot(jail Jail) error { var snaptodel []string // Get all recursive snapshots rs := strings.Split(jail.RootPath, "/") rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/")) cmd := fmt.Sprintf("zfs list -r -H -o name -t snapshot %s", rootDataset) out, err := executeCommand(cmd) if err != nil { fmt.Printf("Error: listing snapshots: %s\n", err.Error()) return nil } for _, line := range strings.Split(out, "\n") { if len(line) > 0 { ls := strings.Split(line, "@") matched, _ := regexp.Match(fmt.Sprintf("^%s(\\/.*)?$", gSnapshotName), []byte(ls[1])) if matched { snaptodel = append(snaptodel, strings.Join(ls, "@")) } } } for _, s := range snaptodel { cmd := fmt.Sprintf("zfs destroy %s", s) _, err := executeCommand(cmd) if err != nil { fmt.Printf("Error deleting snapshot %s: %s\n", s, err.Error()) return nil } fmt.Printf("Snapshot %s deleted\n", s) } return nil }