From d4f6b9ddc783f853f88347dc9e7ebd52d6eea118 Mon Sep 17 00:00:00 2001 From: yo Date: Sat, 18 Jun 2022 16:09:38 +0200 Subject: [PATCH] Add datastore list, filter and sort --- cmd/datastore.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 cmd/datastore.go diff --git a/cmd/datastore.go b/cmd/datastore.go new file mode 100644 index 0000000..8e0f9f3 --- /dev/null +++ b/cmd/datastore.go @@ -0,0 +1,108 @@ +package cmd + +import ( + "fmt" + "errors" + "reflect" + "strconv" + "strings" +) + +func ListDatastores(args []string, display bool) error { + /*************************************************************** + / Filter datastores by names given on command line + /**************************************************************/ + for _, d := range args { + cmd := fmt.Sprintf("zfs list -p -H -o name,used,available,referenced %s", d) + out, err := executeCommand(cmd) + if err != nil { + if strings.HasSuffix(err.Error(), "No such file or directory") { + return errors.New(fmt.Sprintf("Datastore does not exist: %s", d)) + } else { + return errors.New(fmt.Sprintf("Error executing command %s: %v; command returned: %s\n", cmd, err, out)) + } + } + + fields := strings.Fields(out) + if len(fields) < 4 { + return errors.New(fmt.Sprintf("Error parsing output of \"%s\": Not enough fields", cmd)) + } + u, _ := strconv.ParseUint(fields[1], 10, 64) + a, _ := strconv.ParseUint(fields[2], 10, 64) + r, _ := strconv.ParseUint(fields[3], 10, 64) + ds := Datastore{Name: d[1:], Mountpoint: d, ZFSDataset: fields[0], Used: u, Referenced: r, Available: a} + + err = loadDefaultsForDatastore(&ds) + if err != nil { + return err + } + + gDatastores = append(gDatastores, ds) + } + + fields := strings.Split(gDisplayDColumns, ",") + + if true == display { + /*************************************************************** + / Sort datastores + / We support 3 sort criteria max + /**************************************************************/ + if len(gSortDSFields) > 0 && gSortDSFields != "none" { + ds := initDatastoreSortStruct() + + // The way we manage criteria quantity is not very elegant... + var fct1, fct2, fct3 *reflect.Value + for i, c := range strings.Split(gSortDSFields, ",") { + var fctName string + if strings.HasPrefix(c, "-") { + fctName = fmt.Sprintf("%sDec", strings.Replace(c, "-", "", 1)) + } else { // Par defaut (pas de prefix +/-) on considere un tri incremental + fctName = fmt.Sprintf("%sInc", strings.Replace(c, "+", "", 1)) + } + + // Get function by its name + fct, _, err := getStructFieldValue(ds, fctName) + + if err != nil { + fieldName := strings.Replace(strings.Replace(c, "-", "", 1), "+", "", 1) + return errors.New(fmt.Sprintf("ERROR getting DatastoreSort struct field %s. Please check the field name: %s\n", fctName, fieldName)) + } + switch i + 1 { + case 1: + fct1 = fct + case 2: + fct2 = fct + case 3: + fct3 = fct + } + } + + switch len(strings.Split(gSortDSFields, ",")) { + case 1: + DatastoresOrderedBy(fct1.Interface().(datastoreLessFunc)).Sort(gDatastores) + case 2: + DatastoresOrderedBy(fct1.Interface().(datastoreLessFunc), fct2.Interface().(datastoreLessFunc)).Sort(gDatastores) + case 3: + DatastoresOrderedBy(fct1.Interface().(datastoreLessFunc), fct2.Interface().(datastoreLessFunc), fct3.Interface().(datastoreLessFunc)).Sort(gDatastores) + } + } + displayDatastoresFields(gDatastores, fields) + } + + return nil +} + +/******************************************************************************** + * Load jails default config from $datastore/defaults.json + *******************************************************************************/ +func loadDefaultsForDatastore(ds *Datastore) error { + jc, err := getJailConfig(fmt.Sprintf("%s/defaults.json", ds.Mountpoint)) + if err != nil { + return err + } + + ds.DefaultJailConfig = jc + //gDefaultConfig = append(gDefaultConfig, jc) + + return nil +}