Add datastore to snapshots, force Datastore display when jail exist on multi datastores
This commit is contained in:
parent
1c04f62ed8
commit
9218ffafe1
36
cmd/list.go
36
cmd/list.go
@ -3,7 +3,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/viper"
|
|
||||||
"gocage/jail"
|
"gocage/jail"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -40,12 +39,12 @@ func ListJailsProps(args []string) {
|
|||||||
* into gJails global var
|
* into gJails global var
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
func ListJails(args []string, display bool) {
|
func ListJails(args []string, display bool) {
|
||||||
fields := strings.Split(gDisplayJColumns, ",")
|
for _, ds := range gDatastores {
|
||||||
|
listJailsFromDatastore(ds)
|
||||||
for _, d := range viper.GetStringSlice("datastore") {
|
|
||||||
listJailsFromDatastore(d)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fields := strings.Split(gDisplayJColumns, ",")
|
||||||
|
|
||||||
// This is the structure we will filter, then display
|
// This is the structure we will filter, then display
|
||||||
var jails []Jail
|
var jails []Jail
|
||||||
|
|
||||||
@ -91,7 +90,6 @@ func ListJails(args []string, display bool) {
|
|||||||
for _, j := range jails {
|
for _, j := range jails {
|
||||||
if j.Name == a {
|
if j.Name == a {
|
||||||
js = append(js, j)
|
js = append(js, j)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,17 +148,17 @@ func ListJails(args []string, display bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listJailsFromDatastore(datastore string) {
|
func listJailsFromDatastore(ds Datastore) {
|
||||||
fileInfo, err := os.Stat(datastore)
|
fileInfo, err := os.Stat(ds.Mountpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(fmt.Sprintf("Unable to access %s, check path and/or rights", datastore))
|
log.Fatalln(fmt.Sprintf("Unable to access %s, check path and/or rights", ds.Mountpoint))
|
||||||
}
|
}
|
||||||
if fileInfo.IsDir() == false {
|
if fileInfo.IsDir() == false {
|
||||||
log.Fatalln(fmt.Sprintf("%s is not a directory", datastore))
|
log.Fatalln(fmt.Sprintf("%s is not a directory", ds.Mountpoint))
|
||||||
}
|
}
|
||||||
|
|
||||||
// A datastore have to contain a "jails" directory
|
// A datastore have to contain a "jails" directory
|
||||||
jailsDir := fmt.Sprintf("%s/jails", datastore)
|
jailsDir := fmt.Sprintf("%s/jails", ds.Mountpoint)
|
||||||
fileInfo, err = os.Stat(jailsDir)
|
fileInfo, err = os.Stat(jailsDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(fmt.Sprintf("Unable to access %s, check path and/or rights", jailsDir))
|
log.Fatalln(fmt.Sprintf("Unable to access %s, check path and/or rights", jailsDir))
|
||||||
@ -169,10 +167,10 @@ func listJailsFromDatastore(datastore string) {
|
|||||||
log.Fatalln(fmt.Sprintf("%s is not a directory", jailsDir))
|
log.Fatalln(fmt.Sprintf("%s is not a directory", jailsDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
listJailsFromDirectory(jailsDir)
|
listJailsFromDirectory(jailsDir, ds.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listJailsFromDirectory(dir string) []Jail {
|
func listJailsFromDirectory(dir string, dsname string) []Jail {
|
||||||
files, err := ioutil.ReadDir(dir)
|
files, err := ioutil.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(fmt.Sprintf("Unable to browse %s, check path and/or rights", dir))
|
log.Fatalln(fmt.Sprintf("Unable to browse %s, check path and/or rights", dir))
|
||||||
@ -194,6 +192,7 @@ func listJailsFromDirectory(dir string) []Jail {
|
|||||||
Name: jailConf.Host_hostname,
|
Name: jailConf.Host_hostname,
|
||||||
Config: jailConf,
|
Config: jailConf,
|
||||||
ConfigPath: jailConfPath,
|
ConfigPath: jailConfPath,
|
||||||
|
Datastore: dsname,
|
||||||
RootPath: jailRootPath,
|
RootPath: jailRootPath,
|
||||||
Running: false,
|
Running: false,
|
||||||
}
|
}
|
||||||
@ -223,9 +222,12 @@ func listJailsFromDirectory(dir string) []Jail {
|
|||||||
// Check if jail with the same name already exist on another DS
|
// Check if jail with the same name already exist on another DS
|
||||||
for _, jj := range gJails {
|
for _, jj := range gJails {
|
||||||
if strings.EqualFold(jj.Name, j.Name) {
|
if strings.EqualFold(jj.Name, j.Name) {
|
||||||
fmt.Printf("ERROR: A jail with name %s already exist on datastore %s!\n", j.Name, jj.Zpool)
|
fmt.Printf(" ---------------------------------------------- \n")
|
||||||
fmt.Printf("Jail %s on datastore %s wont be handled\n", j.Name, j.Zpool)
|
fmt.Printf("Warning: A jail with name %s already exist on datastore %s!\n", j.Name, jj.Datastore)
|
||||||
return gJails
|
fmt.Printf(" ---------------------------------------------- \n")
|
||||||
|
// Add Datastore to avoid confusion
|
||||||
|
gDisplayJColumns += ",Datastore"
|
||||||
|
gDisplaySColumns += ",Datastore"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ const (
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
func MigrateJail(args []string) {
|
func MigrateJail(args []string) {
|
||||||
var jailNames []string
|
var jailNames []string
|
||||||
var destDS Datastore
|
|
||||||
|
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
@ -27,26 +26,24 @@ func MigrateJail(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, jn := range jailNames {
|
for _, jn := range jailNames {
|
||||||
// Check if destination datastore exist
|
|
||||||
found := false
|
|
||||||
for _, ds := range gDatastores {
|
|
||||||
if strings.EqualFold(gMigrateDestDatastore, ds.Name) {
|
|
||||||
found = true
|
|
||||||
destDS = ds
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if false == found {
|
|
||||||
fmt.Printf("Unkown datastore: %s\n", gMigrateDestDatastore)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cj, err := getJailFromArray(jn, gJails)
|
cj, err := getJailFromArray(jn, gJails)
|
||||||
if cj == nil {
|
if cj == nil {
|
||||||
fmt.Printf("Error getting jail %s: Not found\n", jn)
|
fmt.Printf("Error getting jail %s: Not found\n", jn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if destination datastore exist & get current DS
|
||||||
|
destDS, err := getDatastoreFromArray(gMigrateDestDatastore, gDatastores)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting datastore \"%s\": %v\n", gMigrateDestDatastore, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
curDS, err := getDatastoreFromArray(cj.Datastore, gDatastores)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting datastore \"%s\": %v\n", gMigrateDestDatastore, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if cj.Running == true && gYesToAll == false {
|
if cj.Running == true && gYesToAll == false {
|
||||||
fmt.Printf("WARNING: Jail %s is running\n", cj.Name)
|
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("Migration will stop it for data sync before starting on the new pool. You will be prompted for shutdown.\n")
|
||||||
@ -74,7 +71,7 @@ func MigrateJail(args []string) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Snapshot config
|
// Snapshot config
|
||||||
dsconf := strings.Join([]string{cj.Zpool, "iocage", "jails", jn}, "/")
|
dsconf := strings.Join([]string{curDS.ZFSDataset, "jails", jn}, "/")
|
||||||
fmt.Printf("Snapshot %s: ", dsconf)
|
fmt.Printf("Snapshot %s: ", dsconf)
|
||||||
if err = zfsSnapshot(dsconf, "gocage_mig_init"); err != nil {
|
if err = zfsSnapshot(dsconf, "gocage_mig_init"); err != nil {
|
||||||
fmt.Printf("Error: %v\n", err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
@ -83,7 +80,7 @@ func MigrateJail(args []string) {
|
|||||||
fmt.Printf("Done\n")
|
fmt.Printf("Done\n")
|
||||||
|
|
||||||
// Snapshot filesystem
|
// Snapshot filesystem
|
||||||
dsdata := strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/")
|
dsdata := strings.Join([]string{curDS.ZFSDataset, "iocage", "jails", jn, "root"}, "/")
|
||||||
fmt.Printf("Snapshot %s: ", dsdata)
|
fmt.Printf("Snapshot %s: ", dsdata)
|
||||||
if err := zfsSnapshot(dsdata, "gocage_mig_init"); err != nil {
|
if err := zfsSnapshot(dsdata, "gocage_mig_init"); err != nil {
|
||||||
fmt.Printf("Error: %v\n", err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
@ -178,11 +175,14 @@ func CleanMigrateMess(args []string) error {
|
|||||||
for _, jn := range jailNames {
|
for _, jn := range jailNames {
|
||||||
cj, err := getJailFromArray(jn, gJails)
|
cj, err := getJailFromArray(jn, gJails)
|
||||||
if cj == nil {
|
if cj == nil {
|
||||||
fmt.Printf("Error getting jail %s: Not found\n", jn)
|
|
||||||
return errors.New(fmt.Sprintf("Error getting jail %s: Not found\n", jn))
|
return errors.New(fmt.Sprintf("Error getting jail %s: Not found\n", jn))
|
||||||
}
|
}
|
||||||
|
curDS, err := getDatastoreFromArray(cj.Datastore, gDatastores)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("Error getting datastore \"%s\": %v\n", cj.Datastore, err))
|
||||||
|
}
|
||||||
|
|
||||||
cmd := fmt.Sprintf("zfs destroy %s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn}, "/"))
|
cmd := fmt.Sprintf("zfs destroy %s@gocage_mig_init", strings.Join([]string{curDS.ZFSDataset, "jails", jn}, "/"))
|
||||||
out, err := executeCommand(cmd)
|
out, err := executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
||||||
@ -190,7 +190,7 @@ func CleanMigrateMess(args []string) error {
|
|||||||
return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out))
|
return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_init", strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/"))
|
cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_init", strings.Join([]string{curDS.ZFSDataset, "jails", jn, "root"}, "/"))
|
||||||
out, err = executeCommand(cmd)
|
out, err = executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
||||||
@ -198,7 +198,7 @@ func CleanMigrateMess(args []string) error {
|
|||||||
return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out))
|
return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_last_sync", strings.Join([]string{cj.Zpool, "iocage", "jails", jn}, "/"))
|
cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_last_sync", strings.Join([]string{curDS.ZFSDataset, "jails", jn}, "/"))
|
||||||
out, err = executeCommand(cmd)
|
out, err = executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
||||||
@ -206,7 +206,7 @@ func CleanMigrateMess(args []string) error {
|
|||||||
return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out))
|
return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_last_sync", strings.Join([]string{cj.Zpool, "iocage", "jails", jn, "root"}, "/"))
|
cmd = fmt.Sprintf("zfs destroy %s@gocage_mig_last_sync", strings.Join([]string{curDS.ZFSDataset, "jails", jn, "root"}, "/"))
|
||||||
out, err = executeCommand(cmd)
|
out, err = executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
if false == strings.HasSuffix(out, "could not find any snapshots to destroy; check snapshot names.\n") {
|
||||||
|
@ -225,7 +225,10 @@ You can specify multiple jails.`,
|
|||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// Load inventory
|
// Load inventory
|
||||||
ListJails(args, false)
|
ListJails(args, false)
|
||||||
CleanMigrateMess(args)
|
err := CleanMigrateMess(args)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%v", err)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,8 +265,8 @@ func init() {
|
|||||||
|
|
||||||
// Command dependant switches
|
// Command dependant switches
|
||||||
|
|
||||||
// We reuse these in "gocage snapshot list myjail" and 'gocage datastore list" commands (TODO)
|
// We reuse these flags in "gocage snapshot list myjail" and 'gocage datastore list" commands
|
||||||
listCmd.Flags().StringVarP(&gDisplayJColumns, "outcol", "o", "JID,Name,Config.Release,Config.Ip4_addr,Running", "Show these columns in output")
|
listCmd.Flags().StringVarP(&gDisplayJColumns, "outcol", "o", "JID,Name,Datastore,Config.Release,Config.Ip4_addr,Running", "Show these columns in output")
|
||||||
listCmd.Flags().BoolVarP(&gNoJailLineSep, "nolinesep", "l", false, "Do not display line separator between jails")
|
listCmd.Flags().BoolVarP(&gNoJailLineSep, "nolinesep", "l", false, "Do not display line separator between jails")
|
||||||
listCmd.Flags().StringVarP(&gFilterJails, "filter", "f", "none", "Only display jails with these values. Ex: \"gocage list -f Config.Boot=1\" will only list started on boot jails")
|
listCmd.Flags().StringVarP(&gFilterJails, "filter", "f", "none", "Only display jails with these values. Ex: \"gocage list -f Config.Boot=1\" will only list started on boot jails")
|
||||||
listCmd.Flags().StringVarP(&gSortJailFields, "sort", "s", "none", "Display jails sorted by field values. Ex: \"gocage list -s +Name,-Config.Priority\" will sort jails by their decreasing name, then increasing start priority. 3 critera max supported.")
|
listCmd.Flags().StringVarP(&gSortJailFields, "sort", "s", "none", "Display jails sorted by field values. Ex: \"gocage list -s +Name,-Config.Priority\" will sort jails by their decreasing name, then increasing start priority. 3 critera max supported.")
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
@ -23,6 +24,10 @@ func ListJailsSnapshots(args []string) {
|
|||||||
/**************************************************************/
|
/**************************************************************/
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
|
/*if countOfJailsWithThisName(a) > 1 {
|
||||||
|
fmt.Printf("Nope")
|
||||||
|
return
|
||||||
|
}*/
|
||||||
jailNames = append(jailNames, a)
|
jailNames = append(jailNames, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,23 +104,27 @@ func listJailSnapshots(jail Jail) []Snapshot {
|
|||||||
|
|
||||||
// 1. List all datasets
|
// 1. List all datasets
|
||||||
// TODO : Include mounted filesystems?
|
// TODO : Include mounted filesystems?
|
||||||
rs := strings.Split(jail.RootPath, "/")
|
|
||||||
rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/"))
|
curDS, err := getDatastoreFromArray(jail.Datastore, gDatastores)
|
||||||
cmd := fmt.Sprintf("zfs list -r -H -o name,mountpoint,used,referenced,creation -t snapshot %s", rootDataset)
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting datastore \"%s\": %v\n", jail.Datastore, err)
|
||||||
|
return snapshots
|
||||||
|
}
|
||||||
|
|
||||||
|
rootDataset := fmt.Sprintf("%s/%s/%s", curDS.ZFSDataset, "jails", jail.Name)
|
||||||
|
cmd := fmt.Sprintf("zfs list -p -r -H -o name,mountpoint,used,referenced,creation -t snapshot %s", rootDataset)
|
||||||
out, err := executeCommand(cmd)
|
out, err := executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error: %s\n", err.Error())
|
fmt.Printf("Error: %s\n", err.Error())
|
||||||
return snapshots
|
return snapshots
|
||||||
}
|
}
|
||||||
|
|
||||||
dateLayout := "Mon Jan _2 15:04 2006"
|
|
||||||
loc, _ := time.LoadLocation(gTimeZone)
|
|
||||||
|
|
||||||
for _, line := range strings.Split(out, "\n") {
|
for _, line := range strings.Split(out, "\n") {
|
||||||
if len(line) > 0 {
|
if len(line) > 0 {
|
||||||
ls := strings.Split(line, "\t")
|
ls := strings.Split(line, "\t")
|
||||||
// Parse creation date so we can use it to sort snapshots
|
// Parse creation date so we can use it to sort snapshots
|
||||||
creationts, err := time.ParseInLocation(dateLayout, ls[4], loc)
|
//creationts, err := time.ParseInLocation(dateLayout, ls[4], loc)
|
||||||
|
creationts, err := strconv.ParseInt(ls[4], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error while parsing date %s:", ls[4], err)
|
fmt.Println("Error while parsing date %s:", ls[4], err)
|
||||||
return snapshots
|
return snapshots
|
||||||
@ -123,13 +132,15 @@ func listJailSnapshots(jail Jail) []Snapshot {
|
|||||||
// Get subdir to append to snapshot name
|
// Get subdir to append to snapshot name
|
||||||
subdir := strings.Replace(strings.Split(ls[0], "@")[0], rootDataset, "", 1)
|
subdir := strings.Replace(strings.Split(ls[0], "@")[0], rootDataset, "", 1)
|
||||||
|
|
||||||
snapshots = append(snapshots, Snapshot{Dsname: ls[0],
|
u, _ := strconv.ParseUint(ls[2], 10, 64)
|
||||||
|
r, _ := strconv.ParseUint(ls[3], 10, 64)
|
||||||
|
snapshots = append(snapshots, Snapshot{Datastore: curDS.Name,
|
||||||
Name: fmt.Sprintf("%s%s", strings.Split(ls[0], "@")[1], subdir),
|
Name: fmt.Sprintf("%s%s", strings.Split(ls[0], "@")[1], subdir),
|
||||||
Jailname: jail.Name,
|
Jailname: jail.Name,
|
||||||
Mountpoint: ls[1],
|
Mountpoint: ls[1],
|
||||||
Used: ls[2],
|
Used: u,
|
||||||
Referenced: ls[3],
|
Referenced: r,
|
||||||
Creation: creationts})
|
Creation: time.Unix(creationts, 0)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,8 +176,8 @@ func CreateJailSnapshot(args []string) {
|
|||||||
* Create snapshot for a jail
|
* Create snapshot for a jail
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
func createJailSnapshot(jail Jail) error {
|
func createJailSnapshot(jail Jail) error {
|
||||||
rs := strings.Split(jail.RootPath, "/")
|
curDS, _ := getDatastoreFromArray(jail.Datastore, gDatastores)
|
||||||
rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/"))
|
rootDataset := fmt.Sprintf("%s/%s/%s", curDS.ZFSDataset, "jails", jail.Name)
|
||||||
cmd := fmt.Sprintf("zfs snapshot -r %s@%s", rootDataset, gSnapshotName)
|
cmd := fmt.Sprintf("zfs snapshot -r %s@%s", rootDataset, gSnapshotName)
|
||||||
|
|
||||||
_, err := executeCommand(cmd)
|
_, err := executeCommand(cmd)
|
||||||
@ -207,8 +218,8 @@ func deleteJailSnapshot(jail Jail) error {
|
|||||||
var snaptodel []string
|
var snaptodel []string
|
||||||
|
|
||||||
// Get all recursive snapshots
|
// Get all recursive snapshots
|
||||||
rs := strings.Split(jail.RootPath, "/")
|
curDS, _ := getDatastoreFromArray(jail.Datastore, gDatastores)
|
||||||
rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/"))
|
rootDataset := fmt.Sprintf("%s/%s/%s", curDS.ZFSDataset, "jails", jail.Name)
|
||||||
cmd := fmt.Sprintf("zfs list -r -H -o name -t snapshot %s", rootDataset)
|
cmd := fmt.Sprintf("zfs list -r -H -o name -t snapshot %s", rootDataset)
|
||||||
out, err := executeCommand(cmd)
|
out, err := executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -284,8 +295,8 @@ func rollbackJailSnapshot(jail Jail) error {
|
|||||||
|
|
||||||
// We need to rollback parent and childs
|
// We need to rollback parent and childs
|
||||||
// Get all recursive snapshots
|
// Get all recursive snapshots
|
||||||
rs := strings.Split(jail.RootPath, "/")
|
curDS, _ := getDatastoreFromArray(jail.Datastore, gDatastores)
|
||||||
rootDataset := fmt.Sprintf("%s%s", jail.Zpool, strings.Join(rs[:len(rs)-1], "/"))
|
rootDataset := fmt.Sprintf("%s/%s/%s", curDS.ZFSDataset, "jails", jail.Name)
|
||||||
cmd := fmt.Sprintf("zfs list -r -H -o name -t snapshot %s", rootDataset)
|
cmd := fmt.Sprintf("zfs list -r -H -o name -t snapshot %s", rootDataset)
|
||||||
out, err := executeCommand(cmd)
|
out, err := executeCommand(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -27,7 +27,8 @@ type Jail struct {
|
|||||||
Running bool
|
Running bool
|
||||||
// No need, Config.Release always represent what is running (plus it know release for non-running jails)
|
// No need, Config.Release always represent what is running (plus it know release for non-running jails)
|
||||||
//Release string
|
//Release string
|
||||||
Zpool string
|
Zpool string
|
||||||
|
Datastore string
|
||||||
}
|
}
|
||||||
|
|
||||||
// iocage struct as stored in config.json
|
// iocage struct as stored in config.json
|
||||||
@ -191,11 +192,11 @@ type Mount struct {
|
|||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
// snapshot name is stored after '@' in dataset name
|
// snapshot name is stored after '@' in dataset name
|
||||||
Name string
|
Name string
|
||||||
Dsname string
|
Datastore string
|
||||||
Jailname string
|
Jailname string
|
||||||
Mountpoint string
|
Mountpoint string
|
||||||
Used string
|
Used uint64
|
||||||
Referenced string
|
Referenced uint64
|
||||||
Creation time.Time
|
Creation time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,6 +216,8 @@ type JailSort struct {
|
|||||||
ConfigPathDec jailLessFunc
|
ConfigPathDec jailLessFunc
|
||||||
RunningInc jailLessFunc
|
RunningInc jailLessFunc
|
||||||
RunningDec jailLessFunc
|
RunningDec jailLessFunc
|
||||||
|
DatastoreInc jailLessFunc
|
||||||
|
DatastoreDec jailLessFunc
|
||||||
ZpoolInc jailLessFunc
|
ZpoolInc jailLessFunc
|
||||||
ZpoolDec jailLessFunc
|
ZpoolDec jailLessFunc
|
||||||
Config JailConfigSort
|
Config JailConfigSort
|
||||||
@ -498,8 +501,8 @@ type JailConfigSort struct {
|
|||||||
type SnapshotSort struct {
|
type SnapshotSort struct {
|
||||||
NameInc snapshotLessFunc
|
NameInc snapshotLessFunc
|
||||||
NameDec snapshotLessFunc
|
NameDec snapshotLessFunc
|
||||||
DsnameInc snapshotLessFunc
|
DatastoreInc snapshotLessFunc
|
||||||
DsnameDec snapshotLessFunc
|
DatastoreDec snapshotLessFunc
|
||||||
JailnameInc snapshotLessFunc
|
JailnameInc snapshotLessFunc
|
||||||
JailnameDec snapshotLessFunc
|
JailnameDec snapshotLessFunc
|
||||||
MountpointInc snapshotLessFunc
|
MountpointInc snapshotLessFunc
|
||||||
|
86
cmd/utils.go
86
cmd/utils.go
@ -391,7 +391,7 @@ func getJailFromArray(name string, jarray []Jail) (*Jail, error) {
|
|||||||
return &Jail{}, errors.New("Jail not found")
|
return &Jail{}, errors.New("Jail not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* Generic utilities
|
* Generic utilities
|
||||||
*
|
*
|
||||||
@ -405,6 +405,28 @@ func isStringInArray(strarr []string, searched string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDatastoreFromArray(name string, dsa []Datastore) (*Datastore, error) {
|
||||||
|
for _, d := range dsa {
|
||||||
|
if name == d.Name {
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Datastore{}, errors.New("Datastore not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Return the quantity of jails with the name passed as parameter
|
||||||
|
*****************************************************************************/
|
||||||
|
func countOfJailsWithThisName(name string) int {
|
||||||
|
count := 0
|
||||||
|
for _, j := range gJails {
|
||||||
|
if strings.EqualFold(j.Name, name) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Recurse into structure, returning reflect.Kind of named field.
|
* Recurse into structure, returning reflect.Kind of named field.
|
||||||
* Nested fields are named with a dot (ex "MyStruct.MyField")
|
* Nested fields are named with a dot (ex "MyStruct.MyField")
|
||||||
@ -836,7 +858,7 @@ func displayJailsFields(jails []Jail, valsToDisplay []string) {
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Pretty display of snapshots field
|
* Pretty display of snapshots field
|
||||||
* Fields to show are given in a string array parameter
|
* Fields to show are given in a string array parameter
|
||||||
* Ex. : displaySnapshotsFields(snapshots, ["Name", "Dsname", "Used"])
|
* Ex. : displaySnapshotsFields(snapshots, ["Name", "Datastore", "Used"])
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
func displaySnapshotsFields(snaps []Snapshot, valsToDisplay []string) {
|
func displaySnapshotsFields(snaps []Snapshot, valsToDisplay []string) {
|
||||||
/* A line is defined by :
|
/* A line is defined by :
|
||||||
@ -878,7 +900,14 @@ func displaySnapshotsFields(snaps []Snapshot, valsToDisplay []string) {
|
|||||||
itnr := len(strings.Split(string(a.FieldByName(f).Interface().(string)), ","))
|
itnr := len(strings.Split(string(a.FieldByName(f).Interface().(string)), ","))
|
||||||
field.MaxLen = len(fmt.Sprintf("%v", a.FieldByName(f).Interface())) / itnr
|
field.MaxLen = len(fmt.Sprintf("%v", a.FieldByName(f).Interface())) / itnr
|
||||||
} else {
|
} else {
|
||||||
field.MaxLen = len(fmt.Sprintf("%v", a.FieldByName(f).Interface()))
|
// Special case of disk size : We will print human readable values
|
||||||
|
if field.Name == "Used" || field.Name == "Referenced" || field.Name == "Available" {
|
||||||
|
var v datasize.ByteSize
|
||||||
|
v.UnmarshalText([]byte(fmt.Sprintf("%v", a.FieldByName(f).Interface())))
|
||||||
|
field.MaxLen = len(fmt.Sprintf("%v", v.HumanReadable()))
|
||||||
|
} else {
|
||||||
|
field.MaxLen = len(fmt.Sprintf("%v", a.FieldByName(f).Interface()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
field.Value = fmt.Sprintf("%v", a.FieldByName(f).Interface())
|
field.Value = fmt.Sprintf("%v", a.FieldByName(f).Interface())
|
||||||
} else {
|
} else {
|
||||||
@ -983,25 +1012,24 @@ func displaySnapshotsFields(snaps []Snapshot, valsToDisplay []string) {
|
|||||||
fmt.Printf("|")
|
fmt.Printf("|")
|
||||||
}
|
}
|
||||||
// Special cases of value displaying
|
// Special cases of value displaying
|
||||||
/* if f.Name == "JID" && f.Value == "0" {
|
// Pretty print of sizes
|
||||||
fmt.Printf(" ")
|
if f.Name == "Used" || f.Name == "Referenced" || f.Name == "Available" {
|
||||||
} else if f.Name == "Ip4_addr" {
|
var v datasize.ByteSize
|
||||||
ia := strings.Split(f.Value, ",")
|
err := v.UnmarshalText([]byte(f.Value))
|
||||||
// If we have more than 1 value we need to finish this line, and store value for writing at the end of line loop
|
if err != nil {
|
||||||
for i, inter := range ia {
|
return
|
||||||
if i > 0 {
|
}
|
||||||
supplines[f.Name] = inter
|
fmt.Printf(" %s", v.HumanReadable())
|
||||||
} else {
|
// Complete with spaces to the max length
|
||||||
fmt.Printf(" %s", inter)
|
for i := len(v.HumanReadable()) + 1; i < f.MaxLen+1; i++ {
|
||||||
}
|
fmt.Printf(" ")
|
||||||
}
|
}
|
||||||
//fmt.Printf(" %s", strings.Split(strings.Split(f.Value, "|")[1], "/")[0])
|
} else {
|
||||||
} else {*/
|
fmt.Printf(" %s", f.Value)
|
||||||
fmt.Printf(" %s", f.Value)
|
// Complete with spaces to the max length
|
||||||
/*}*/
|
for i := len(f.Value) + 1; i < f.MaxLen+1; i++ {
|
||||||
// Complete with spaces to the max length
|
fmt.Printf(" ")
|
||||||
for i := len(f.Value) + 1; i < f.MaxLen+1; i++ {
|
}
|
||||||
fmt.Printf(" ")
|
|
||||||
}
|
}
|
||||||
fmt.Printf(" |")
|
fmt.Printf(" |")
|
||||||
}
|
}
|
||||||
@ -2125,6 +2153,12 @@ func initJailSortStruct() JailSort {
|
|||||||
ConfigPathDec: func(j1, j2 *Jail) bool {
|
ConfigPathDec: func(j1, j2 *Jail) bool {
|
||||||
return j1.ConfigPath > j2.ConfigPath
|
return j1.ConfigPath > j2.ConfigPath
|
||||||
},
|
},
|
||||||
|
DatastoreInc: func(j1, j2 *Jail) bool {
|
||||||
|
return j1.Datastore < j2.Datastore
|
||||||
|
},
|
||||||
|
DatastoreDec: func(j1, j2 *Jail) bool {
|
||||||
|
return j1.Datastore > j2.Datastore
|
||||||
|
},
|
||||||
InternalNameInc: func(j1, j2 *Jail) bool {
|
InternalNameInc: func(j1, j2 *Jail) bool {
|
||||||
return j1.InternalName < j2.InternalName
|
return j1.InternalName < j2.InternalName
|
||||||
},
|
},
|
||||||
@ -2241,11 +2275,11 @@ func initSnapshotSortStruct() SnapshotSort {
|
|||||||
NameDec: func(s1, s2 *Snapshot) bool {
|
NameDec: func(s1, s2 *Snapshot) bool {
|
||||||
return s1.Name > s2.Name
|
return s1.Name > s2.Name
|
||||||
},
|
},
|
||||||
DsnameInc: func(s1, s2 *Snapshot) bool {
|
DatastoreInc: func(s1, s2 *Snapshot) bool {
|
||||||
return s1.Dsname < s2.Dsname
|
return s1.Datastore < s2.Datastore
|
||||||
},
|
},
|
||||||
DsnameDec: func(s1, s2 *Snapshot) bool {
|
DatastoreDec: func(s1, s2 *Snapshot) bool {
|
||||||
return s1.Dsname > s2.Dsname
|
return s1.Datastore > s2.Datastore
|
||||||
},
|
},
|
||||||
JailnameInc: func(s1, s2 *Snapshot) bool {
|
JailnameInc: func(s1, s2 *Snapshot) bool {
|
||||||
return s1.Jailname < s2.Jailname
|
return s1.Jailname < s2.Jailname
|
||||||
|
Loading…
Reference in New Issue
Block a user