package cmd import ( "os" "fmt" "strings" "bufio" /* "errors" "regexp" "time" */ ) const ( // 1MB BUFFER_SIZE = 512 ) /******************************************************************************** * Migrate jail to another zfs pool *******************************************************************************/ func MigrateJail(args []string) { var jailNames []string if len(args) > 0 { for _, a := range args { jailNames = append(jailNames, a) } } for _, jn := range jailNames { // Check if destination dataset exist cmd := fmt.Sprintf("zfs list %s/iocage/jails", gMigrateDestPool) out, err := executeCommand(cmd) if err != nil { fmt.Printf("Error executing command %s: %v; command returned: %s\n", cmd, err, out) return } cj, err := getJailFromArray(jn, gJails) if cj == nil { fmt.Printf("Error getting jail %s: Not found\n", jn) return } if cj.Running == true { fmt.Printf("WARNING: Jail %s is running\n", cj.Name) fmt.Printf("Migration will stop it for data sync before starting on the new pool. You will be prompted for shutdown\n") fmt.Printf("Continue? (y/n) ") scanr := bufio.NewScanner(os.Stdin) scanr.Scan() if false == strings.EqualFold(scanr.Text(), "y") { fmt.Printf("Migration aborted\n") return } } /* TODO : Check dest pool (gMigrateDestPool) existence zfs snapshot /iocage/jails/$jail@gocage_mig_first_snap zfs snapshot /iocage/jails/$jail/root@gocage_mig_first_snap zfs send jail@gocage_mig_first_snap | zfs receive destpool/jails/jail_name zfs send jail/root@@gocage_mig_first_snap | zfs receive destpool/jails/jail_name/root shutdown jail if needed if jail was shutdown zfs snapshot /iocage/jails/$jail@gocage_mig_last_snap to get last data zfs send jail/root@gocage_mig_last_snap | zfs receive -F destpool/jails/jail_name start jail on new dest zfs destroy destpool/jails/jail_name@gocage_mig_first_snap zfs destroy destpool/jails/jail_name/root@gocage_mig_first_snap */ // Snapshot config dsconf := strings.Join([]string{cj.Zpool, "iocage", "jails", jn}, "/") fmt.Printf("Snapshot %s: ", dsconf) if err = zfsSnapshot(dsconf, "gocage_mig_init"); err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Done\n") // Snapshot filesystem dsdata := strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/") fmt.Printf("Snapshot %s: ", dsdata) if err := zfsSnapshot(dsdata, "gocage_mig_init"); err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Done\n") dsconfdest := strings.Join([]string{gMigrateDestPool, "iocage", "jails", jn}, "/") fmt.Printf("Migrate jail config dataset to %s: ", dsconfdest) if err := zfsCopy(fmt.Sprintf("%s@gocage_mig_init", dsconf), dsconfdest); err != nil { fmt.Printf("Error: %v\n", err) } fmt.Printf("Done\n") dsdatadest := strings.Join([]string{gMigrateDestPool, "iocage", "jails", jn, "root"}, "/") fmt.Printf("Migrate jail filesystem dataset to %s: ", dsdatadest) if err := zfsCopy(fmt.Sprintf("%s@gocage_mig_init", dsdata), dsdatadest); err != nil { fmt.Printf("Error: %v\n", err) } fmt.Printf("Done\n") } } // Clean snapshots from an aborted migration func CleanMigrateMess(args []string) { var jailNames []string if len(args) > 0 { for _, a := range args { jailNames = append(jailNames, a) } } for _, jn := range jailNames { cj, err := getJailFromArray(jn, gJails) if cj == nil { fmt.Printf("Error getting jail %s: Not found\n", jn) return } cmd := fmt.Sprintf("zfs destroy %s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn}, "/")) out, err := executeCommand(cmd) if err != nil { if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") { fmt.Printf("Error executing command %s: %v; command returned: %s\n", cmd, err, out) return } } cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/")) out, err = executeCommand(cmd) if err != nil { if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") { fmt.Printf("Error executing command %s: %v; command returned: %s\n", cmd, err, out) return } } } }