"gocage migrate jail -d destination_dataset" working for cold migrations

This commit is contained in:
yo 2022-06-05 14:10:07 +02:00
parent fb3ee07585
commit 31fa6904db

183
cmd/migrate.go Normal file
View File

@ -0,0 +1,183 @@
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
var cj *Jail
if len(args) > 0 {
for _, a := range args {
jailNames = append(jailNames, a)
}
}
for _, jn := range jailNames {
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)
for i, j := range gJails {
if strings.EqualFold(j.Name, jn) {
cj = &gJails[i]
break
}
}
if cj == nil {
fmt.Printf("Error getting jail %s: Not found\n", jn)
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")
/* // First, declare sending process & pipe
cmd_send = exec.Command("zfs", "send", fmt.Sprintf("%s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/")))
stdout_send, err = cmd_send.StdoutPipe()
if err != nil {
fmt.Printf("Error executing command \"zfs send %s\": %v\n", fmt.Sprintf("%s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/")), err)
return
}
// then declare receiving process & pipe
cmd_recv = exec.Command("zfs", "receive", strings.Join([]string{gMigrateDestPool, "iocage", "jails", jn, "root"}, "/"))
stdin_recv, err = cmd_recv.StdinPipe()
if err != nil {
fmt.Printf("Error executing command \"zfs receive %s\": %v\n", strings.Join([]string{gMigrateDestPool, "iocage", "jails", jn, "root"}, "/"), err)
return
}
// Copy data in a go routine
go io.Copy(stdin_recv, stdout_send)
// then start processes and wait for finish
fmt.Printf("DEBUG: Start \"zfs receive %s\"\n", strings.Join([]string{gMigrateDestPool, "iocage", "jails", jn, "root"}, "/"))
if err := cmd_recv.Start(); err != nil {
fmt.Printf("Error starting zfs recv: %v\n", err)
return
}
fmt.Printf("DEBUG: Start \"zfs send %s\"\n", fmt.Sprintf("%s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/")))
if err := cmd_send.Start(); err != nil {
fmt.Printf("Error starting zfs send: %v\n", err)
return
}
fmt.Printf("DEBUG: Wait for zfs send to finish\n")
if err := cmd_send.Wait(); err != nil {
fmt.Printf("Error: zfs send halted with %s\n", err)
return
}
fmt.Printf("DEBUG: Wait for zfs recv to finish\n")
if err := cmd_recv.Wait(); err != nil {
fmt.Printf("Error: zfs recv halted with %s\n", err)
return
}
*/
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
var cj *Jail
if len(args) > 0 {
for _, a := range args {
jailNames = append(jailNames, a)
}
}
for _, jn := range jailNames {
for i, j := range gJails {
if strings.EqualFold(j.Name, jn) {
cj = &gJails[i]
break
}
}
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.EqualFold(out, "could not find any snapshots to destroy; check snapshot names.") {
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.EqualFold(out, "could not find any snapshots to destroy; check snapshot names.") {
fmt.Printf("Error executing command %s: %v; command returned: %s\n", cmd, err, out)
return
}
}
}
}