From 0e8bf8e8a20be91b8751f5566b72b143f0550fed Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Tue, 20 Jan 2026 18:23:09 +0100 Subject: [PATCH 1/5] Accept multiple keys in the datastore key remove commands * om remove --key ... --key ... * om key remove --name ... --name ... --- core/commoncmd/flags.go | 8 ++++++++ core/om/factory.go | 4 ++-- core/omcmd/object_key_remove.go | 9 +++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/core/commoncmd/flags.go b/core/commoncmd/flags.go index 399af8e56..ed6adf083 100644 --- a/core/commoncmd/flags.go +++ b/core/commoncmd/flags.go @@ -190,6 +190,10 @@ func FlagKey(flags *pflag.FlagSet, p *string) { flags.StringVar(p, "key", "", "a data key name") } +func FlagKeys(flags *pflag.FlagSet, p *[]string) { + flags.StringSliceVar(p, "key", nil, "a data key name") +} + func FlagKeyTo(flags *pflag.FlagSet, p *string) { flags.StringVar(p, "to", "", "the new data key name") } @@ -382,6 +386,10 @@ func FlagKeyName(flags *pflag.FlagSet, p *string) { flags.StringVar(p, "name", "", "the key name") } +func FlagKeyNames(flags *pflag.FlagSet, p *[]string) { + flags.StringSliceVar(p, "name", nil, "a data key name") +} + func FlagKeyValue(flags *pflag.FlagSet, p *string) { flags.StringVar(p, "value", "", "the key value") } diff --git a/core/om/factory.go b/core/om/factory.go index 569ea86d4..2fcabed88 100644 --- a/core/om/factory.go +++ b/core/om/factory.go @@ -401,7 +401,7 @@ func newCmdObjectKeyRemove(kind string) *cobra.Command { } flags := cmd.Flags() addFlagsGlobal(flags, &options.OptsGlobal) - commoncmd.FlagKeyName(flags, &options.Name) + commoncmd.FlagKeyNames(flags, &options.Names) return cmd } @@ -3536,7 +3536,7 @@ func newCmdDataStoreRemove(kind string) *cobra.Command { } flags := cmd.Flags() addFlagsGlobal(flags, &options.OptsGlobal) - commoncmd.FlagKey(flags, &options.Name) + commoncmd.FlagKeys(flags, &options.Names) return cmd } diff --git a/core/omcmd/object_key_remove.go b/core/omcmd/object_key_remove.go index 1cddf49d6..1a6b43640 100644 --- a/core/omcmd/object_key_remove.go +++ b/core/omcmd/object_key_remove.go @@ -12,7 +12,7 @@ import ( type ( CmdObjectKeyRemove struct { OptsGlobal - Name string + Names []string } ) @@ -27,7 +27,12 @@ func (t *CmdObjectKeyRemove) Run(kind string) error { if err != nil { return nil, err } - return nil, store.RemoveKey(t.Name) + for _, name := range t.Names { + if err := store.TransactionRemoveKey(name); err != nil { + return nil, err + } + } + return nil, store.Config().CommitInvalid() }), ).Do() } From e5d19a14bdd4761f1630f9d8da52fd6f2ab5c40d Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Tue, 20 Jan 2026 18:43:12 +0100 Subject: [PATCH 2/5] Accept multiple keys in the datastore key remove commands * ox remove --key ... --key ... * ox key remove --name ... --name ... --- core/ox/factory.go | 4 ++-- core/oxcmd/object_key_remove.go | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/core/ox/factory.go b/core/ox/factory.go index 235355ae5..498fea5c6 100644 --- a/core/ox/factory.go +++ b/core/ox/factory.go @@ -305,7 +305,7 @@ func newCmdObjectKeyRemove(kind string) *cobra.Command { } flags := cmd.Flags() addFlagsGlobal(flags, &options.OptsGlobal) - commoncmd.FlagKeyName(flags, &options.Name) + commoncmd.FlagKeyNames(flags, &options.Names) return cmd } @@ -3289,7 +3289,7 @@ func newCmdDataStoreRemove(kind string) *cobra.Command { } flags := cmd.Flags() addFlagsGlobal(flags, &options.OptsGlobal) - commoncmd.FlagKey(flags, &options.Name) + commoncmd.FlagKeys(flags, &options.Names) return cmd } diff --git a/core/oxcmd/object_key_remove.go b/core/oxcmd/object_key_remove.go index 57afc6efe..bd3826d90 100644 --- a/core/oxcmd/object_key_remove.go +++ b/core/oxcmd/object_key_remove.go @@ -1,7 +1,9 @@ package oxcmd import ( + "bytes" "context" + "encoding/json" "fmt" "net/http" "slices" @@ -16,7 +18,7 @@ import ( type ( CmdObjectKeyRemove struct { OptsGlobal - Name string + Names []string } ) @@ -46,10 +48,18 @@ func (t *CmdObjectKeyRemove) Run(kind string) error { } func (t *CmdObjectKeyRemove) RunForPath(ctx context.Context, c *client.T, path naming.Path) error { - params := api.DeleteObjectDataKeyParams{ - Name: t.Name, + data := make(api.PatchDataKeys, len(t.Names)) + for i, name := range t.Names { + data[i] = api.PatchDataKey{ + Action: "remove", + Name: name, + } + } + r := bytes.NewBuffer(nil) + if err := json.NewEncoder(r).Encode(data); err != nil { + return err } - response, err := c.DeleteObjectDataKeyWithResponse(ctx, path.Namespace, path.Kind, path.Name, ¶ms) + response, err := c.PatchObjectDataWithBodyWithResponse(ctx, path.Namespace, path.Kind, path.Name, "application/json", r) if err != nil { return err } From 60f0b85092987506d28f11a9fb94b9fb9ef2728e Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Wed, 21 Jan 2026 16:20:09 +0100 Subject: [PATCH 3/5] Fix the disk.drbd Provision() idempotency Don't run "drbdadm up" on a already defined res in the provision codepath. --- drivers/resdiskdrbd/main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/resdiskdrbd/main.go b/drivers/resdiskdrbd/main.go index 87d54f334..a1d94bb40 100644 --- a/drivers/resdiskdrbd/main.go +++ b/drivers/resdiskdrbd/main.go @@ -917,8 +917,13 @@ func (t *T) provisionCommon(ctx context.Context) error { if err := t.CreateMD(ctx); err != nil { return err } - if err := t.Up(ctx); err != nil { + dev := t.drbd(ctx) + if isDefined, err := dev.IsDefined(ctx); err != nil { return err + } else if !isDefined { + if err := dev.Up(ctx); err != nil { + return err + } } return nil } From dac071620f056876577d39591063e5a98b48c759 Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Wed, 21 Jan 2026 16:21:54 +0100 Subject: [PATCH 4/5] Fix the disk.loop Provision() idempotency Don't create the loop file if it already exists. Resize it only if we just created it. --- drivers/resdiskloop/main.go | 38 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/resdiskloop/main.go b/drivers/resdiskloop/main.go index 0444d1154..6732054a6 100644 --- a/drivers/resdiskloop/main.go +++ b/drivers/resdiskloop/main.go @@ -248,23 +248,31 @@ func (t *T) provision(ctx context.Context) error { if err = t.provisionDir(ctx); err != nil { return err } - t.Log().Infof("create file %s", t.File) - if f, err = os.Create(t.File); err != nil { - return err - } - defer f.Close() - actionrollback.Register(ctx, func(ctx context.Context) error { - t.Log().Infof("unlink file %s", t.File) - return os.Remove(t.File) - }) - offset := (size / 512 * 512) - 1 - t.Log().Infof("seek/write file, offset %d", offset) - if _, err = f.Seek(offset, 0); err != nil { - return err - } - if _, err = f.Write([]byte{0}); err != nil { + if v, err := file.ExistsAndRegular(t.File); err != nil { return err + } else if v { + t.Log().Infof("file already exists %s", t.File) + } else { + t.Log().Infof("create file %s", t.File) + f, err = os.Create(t.File) + if err != nil { + return err + } + defer f.Close() + actionrollback.Register(ctx, func(ctx context.Context) error { + t.Log().Infof("unlink file %s", t.File) + return os.Remove(t.File) + }) + offset := (size / 512 * 512) - 1 + t.Log().Infof("seek/write file, offset %d", offset) + if _, err = f.Seek(offset, 0); err != nil { + return err + } + if _, err = f.Write([]byte{0}); err != nil { + return err + } } + if err := t.setFileMode(); err != nil { return err } From 7cf449c6c741d4eb228a1babb241ff46fa3ad503 Mon Sep 17 00:00:00 2001 From: Christophe Varoqui Date: Wed, 21 Jan 2026 17:05:50 +0100 Subject: [PATCH 5/5] Define a pool.Capability type * Fix pool.shm formatting size=300mi mntopt, which is not accepted by the linux kernel. * Add a "volatile" volume resource keyword. Set to true instead of type=shm for better abstraction. * Add a "volatile" pool capability, exposed by pool.shm * Add a "file" capability, exposed by all pool drivers so far, but could be useful when a pool.virtual template has no fs resource. * Fix the pool candidates sort to not select shared pools first when the requester does not need shared. --- core/pool/lookup.go | 58 +++++++++++++++++++++++---------- core/pool/main.go | 39 ++++++++++++++-------- core/tui/pool.go | 2 +- daemon/daemonapi/get_pool.go | 12 +++++-- drivers/pooldirectory/main.go | 11 +++++-- drivers/pooldrbd/main.go | 14 ++++++-- drivers/poolfreenas/main.go | 13 ++++++-- drivers/poolhoc/main.go | 13 ++++++-- drivers/poolloop/main.go | 11 +++++-- drivers/poolpure/main.go | 13 ++++++-- drivers/poolrados/main.go | 13 ++++++-- drivers/poolshm/main.go | 14 ++++++-- drivers/poolsymmetrix/main.go | 12 +++++-- drivers/poolvg/main.go | 11 +++++-- drivers/poolvirtual/main.go | 9 +++-- drivers/poolzpool/main.go | 12 +++++-- drivers/resvol/main.go | 2 ++ drivers/resvol/manifest.go | 9 +++++ drivers/resvol/text/kw/volatile | 2 ++ 19 files changed, 211 insertions(+), 59 deletions(-) create mode 100644 drivers/resvol/text/kw/volatile diff --git a/core/pool/lookup.go b/core/pool/lookup.go index 03eba80e1..93f398177 100644 --- a/core/pool/lookup.go +++ b/core/pool/lookup.go @@ -17,14 +17,15 @@ type ( Pools() []Pooler } Lookup struct { - Name string - Type string - Access volaccess.T - Size int64 - Format bool - Shared bool - Usage bool - Nodes []string + Name string + Type string + Access volaccess.T + Size int64 + Format bool + Shared bool + Usage bool + Volatile bool + Nodes []string manager manager } @@ -36,6 +37,19 @@ type ( } ) +const ( + CapBlk Capability = "blk" + CapFile Capability = "file" + CapMove Capability = "move" + CapROO Capability = "roo" + CapROX Capability = "rox" + CapRWO Capability = "rwo" + CapRWX Capability = "rwx" + CapShared Capability = "shared" + CapSnap Capability = "snap" + CapVolatile Capability = "volatile" +) + func (by By) Sort(l StatusList) { s := &statusSorter{ data: l, @@ -72,10 +86,6 @@ func (t Lookup) Do(ctx context.Context) (Pooler, error) { cause = append(cause, fmt.Sprintf("[%s] not matching name %s", p.Name(), t.Name)) continue } - if t.Type == "" && "shm" == p.Type() { - cause = append(cause, fmt.Sprintf("[%s] volatile, type not requested, assume persistence is expected.", p.Name())) - continue - } if t.Type != "" && t.Type != p.Type() { cause = append(cause, fmt.Sprintf("[%s] type %s not matching %s", p.Name(), p.Type(), t.Type)) continue @@ -84,14 +94,26 @@ func (t Lookup) Do(ctx context.Context) (Pooler, error) { cause = append(cause, fmt.Sprintf("[%s] not %s capable %s", p.Name(), t.Access, p.Capabilities())) continue } - if t.Format == false && !HasCapability(p, "blk") { + if t.Format == false && !HasCapability(p, CapBlk) { cause = append(cause, fmt.Sprintf("[%s] not blk capable", p.Name())) continue } - if t.Shared == true && !HasCapability(p, "shared") { + if t.Format == true && !HasCapability(p, CapFile) { + cause = append(cause, fmt.Sprintf("[%s] not file capable", p.Name())) + continue + } + if t.Shared == true && !HasCapability(p, CapShared) { cause = append(cause, fmt.Sprintf("[%s] not shared capable", p.Name())) continue } + if t.Volatile == true && !HasCapability(p, CapVolatile) { + cause = append(cause, fmt.Sprintf("[%s] not volatile capable", p.Name())) + continue + } + if t.Volatile == false && HasCapability(p, CapVolatile) { + cause = append(cause, fmt.Sprintf("[%s] not persistent capable", p.Name())) + continue + } if t.Usage == true { usage, err := p.Usage(ctx) if err != nil { @@ -112,8 +134,8 @@ func (t Lookup) Do(ctx context.Context) (Pooler, error) { } weight := func(p1, p2 *StatusItem) bool { if !t.Shared { - p1shared := p1.HasCapability("shared") - p2shared := p2.HasCapability("shared") + p1shared := p1.HasCapability(CapShared) + p2shared := p2.HasCapability(CapShared) switch { case p1shared && p2shared: // not decisive @@ -121,10 +143,10 @@ func (t Lookup) Do(ctx context.Context) (Pooler, error) { // not decisive case p1shared && !p2shared: // prefer p2, not shared-capable - return true + return false case !p1shared && p2shared: // prefer p1, not shared-capable - return false + return true } } if p1.Usage.Free < p2.Usage.Free { diff --git a/core/pool/main.go b/core/pool/main.go index a2db051de..af0dd32d1 100644 --- a/core/pool/main.go +++ b/core/pool/main.go @@ -39,12 +39,12 @@ type ( Status struct { Usage - Capabilities []string `json:"capabilities"` - Errors []string `json:"errors"` - Head string `json:"head"` - Type string `json:"type"` - UpdatedAt time.Time `json:"updated_at"` - VolumeCount int `json:"volume_count"` + Capabilities Capabilities `json:"capabilities"` + Errors []string `json:"errors"` + Head string `json:"head"` + Type string `json:"type"` + UpdatedAt time.Time `json:"updated_at"` + VolumeCount int `json:"volume_count"` } StatusItem struct { Status @@ -52,7 +52,8 @@ type ( } StatusList []StatusItem - Capabilities []string + Capabilities []Capability + Capability string VolumeStatus struct { Pool string `json:"pool"` @@ -85,7 +86,7 @@ type ( Type() string Head() string Mappings() map[string]string - Capabilities() []string + Capabilities() Capabilities Usage(context.Context) (Usage, error) SetConfig(Config) Config() Config @@ -120,6 +121,18 @@ type ( } ) +func (t Capabilities) StringSlice() []string { + l := make([]string, len(t)) + for i, c := range t { + l[i] = string(c) + } + return l +} + +func (t Capabilities) String() string { + return strings.Join(t.StringSlice(), ",") +} + func MappingsFromPaths(paths san.Paths) (array.Mappings, error) { m := make(array.Mappings) for _, path := range paths.MappingList() { @@ -458,10 +471,10 @@ func (t VolumeStatusList) Swap(i, j int) { } func HasAccess(p Pooler, acs volaccess.T) bool { - return HasCapability(p, acs.String()) + return HasCapability(p, Capability(acs.String())) } -func HasCapability(p Pooler, s string) bool { +func HasCapability(p Pooler, s Capability) bool { for _, capa := range p.Capabilities() { if capa == s { return true @@ -472,10 +485,10 @@ func HasCapability(p Pooler, s string) bool { } func (t *Status) HasAccess(acs volaccess.T) bool { - return t.HasCapability(acs.String()) + return t.HasCapability(Capability(acs.String())) } -func (t *Status) HasCapability(s string) bool { +func (t *Status) HasCapability(s Capability) bool { for _, capa := range t.Capabilities { if capa == s { return true @@ -490,7 +503,7 @@ func (t *Status) DeepCopy() *Status { Type: t.Type, Head: t.Head, VolumeCount: t.VolumeCount, - Capabilities: append([]string{}, t.Capabilities...), + Capabilities: append(Capabilities{}, t.Capabilities...), UpdatedAt: t.UpdatedAt, Usage: Usage{ Free: t.Usage.Free, diff --git a/core/tui/pool.go b/core/tui/pool.go index 692da8f49..021d313b2 100644 --- a/core/tui/pool.go +++ b/core/tui/pool.go @@ -91,7 +91,7 @@ func (t *App) updatePoolList(forceUpdate bool) { return []string{ poolName, poolData.Type, - strings.Join(poolData.Capabilities, ","), + poolData.Capabilities.String(), poolData.Head, strconv.FormatInt(int64(poolData.VolumeCount), 10), sizeconv.BSizeCompact(float64(poolData.Size)), diff --git a/daemon/daemonapi/get_pool.go b/daemon/daemonapi/get_pool.go index 0bf6c2855..9e4dbb531 100644 --- a/daemon/daemonapi/get_pool.go +++ b/daemon/daemonapi/get_pool.go @@ -59,8 +59,12 @@ func (a *DaemonAPI) getNodePools(ctx echo.Context, name *string, nodeMap nodesel continue } stat := *e.Value + capabilities := make([]string, len(stat.Capabilities)) + for i, c := range stat.Capabilities { + capabilities[i] = string(c) + } item := api.Pool{ - Capabilities: append([]string{}, stat.Capabilities...), + Capabilities: capabilities, Free: stat.Free, Head: stat.Head, Name: e.Name, @@ -89,9 +93,13 @@ func (a *DaemonAPI) getClusterPools(ctx echo.Context, name *string) api.PoolItem } item, ok := m[e.Name] stat := *e.Value + capabilities := make([]string, len(stat.Capabilities)) + for i, c := range stat.Capabilities { + capabilities[i] = string(c) + } if !ok { item = api.Pool{ - Capabilities: append([]string{}, stat.Capabilities...), + Capabilities: capabilities, Free: stat.Free, Head: stat.Head, Name: e.Name, diff --git a/drivers/pooldirectory/main.go b/drivers/pooldirectory/main.go index 3a0be14a6..c9ab490e2 100644 --- a/drivers/pooldirectory/main.go +++ b/drivers/pooldirectory/main.go @@ -40,8 +40,15 @@ func (t T) Head() string { return t.path() } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/pooldrbd/main.go b/drivers/pooldrbd/main.go index 018ecb076..09193ac9d 100644 --- a/drivers/pooldrbd/main.go +++ b/drivers/pooldrbd/main.go @@ -42,8 +42,18 @@ func New() *T { return &t } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "snap", "blk", "shared"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapMove, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapShared, + pool.CapSnap, + } } func (t T) vg() string { diff --git a/drivers/poolfreenas/main.go b/drivers/poolfreenas/main.go index 35ea6ba37..cd7d99ee9 100644 --- a/drivers/poolfreenas/main.go +++ b/drivers/poolfreenas/main.go @@ -73,8 +73,17 @@ func (t T) arrayName() string { return t.GetString("array") } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk", "iscsi", "shared"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapMove, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapShared, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/poolhoc/main.go b/drivers/poolhoc/main.go index c327ed3f2..8c2b53a47 100644 --- a/drivers/poolhoc/main.go +++ b/drivers/poolhoc/main.go @@ -83,8 +83,17 @@ func (t T) arrayName() string { return t.GetString("array") } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk", "fc", "shared"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapMove, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapShared, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/poolloop/main.go b/drivers/poolloop/main.go index 4027cf806..ac9fd1aac 100644 --- a/drivers/poolloop/main.go +++ b/drivers/poolloop/main.go @@ -41,8 +41,15 @@ func (t T) Head() string { return t.path() } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/poolpure/main.go b/drivers/poolpure/main.go index 3e6950e9f..8543e091a 100644 --- a/drivers/poolpure/main.go +++ b/drivers/poolpure/main.go @@ -70,8 +70,17 @@ func (t T) arrayName() string { return t.GetString("array") } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk", "fc", "shared"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapMove, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapShared, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/poolrados/main.go b/drivers/poolrados/main.go index c46670ddb..d6f87efdb 100644 --- a/drivers/poolrados/main.go +++ b/drivers/poolrados/main.go @@ -57,8 +57,17 @@ func (t T) rbdNamespace() string { return t.GetString("rbd_namespace") } -func (t T) Capabilities() []string { - return []string{"move", "rox", "rwx", "roo", "rwo", "snap", "blk", "shared"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapMove, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapShared, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/poolshm/main.go b/drivers/poolshm/main.go index 7a63d400a..490f8e7f2 100644 --- a/drivers/poolshm/main.go +++ b/drivers/poolshm/main.go @@ -41,8 +41,16 @@ func (t T) Head() string { return t.path() } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapVolatile, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { @@ -62,7 +70,7 @@ func (t T) Usage(ctx context.Context) (pool.Usage, error) { } func (t *T) mntOpt(size int64) string { - sizeOpt := "size=" + sizeconv.ExactBSizeCompact(float64(size)) + sizeOpt := "size=" + strings.TrimRight(sizeconv.ExactBSizeCompact(float64(size)), "i") opts := t.GetString("mnt_opt") if opts == "" { opts = "mode=700" diff --git a/drivers/poolsymmetrix/main.go b/drivers/poolsymmetrix/main.go index 42c3c2d9f..50b00ed40 100644 --- a/drivers/poolsymmetrix/main.go +++ b/drivers/poolsymmetrix/main.go @@ -130,8 +130,16 @@ func (t T) arrayNodes(nodenames []string) (map[string][]string, error) { return m, nil } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk", "fc", "shared"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapShared, + } } func (t T) getSRP(ctx context.Context) (arraysymmetrix.SRP, error) { diff --git a/drivers/poolvg/main.go b/drivers/poolvg/main.go index 92c14bb04..bfd48a63e 100644 --- a/drivers/poolvg/main.go +++ b/drivers/poolvg/main.go @@ -40,8 +40,15 @@ func (t T) Head() string { return t.VGName() } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "blk"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + } } func (t T) VGName() string { diff --git a/drivers/poolvirtual/main.go b/drivers/poolvirtual/main.go index bb6488bfb..e4699e51f 100644 --- a/drivers/poolvirtual/main.go +++ b/drivers/poolvirtual/main.go @@ -53,8 +53,13 @@ func (t T) volumeEnv() []string { return t.GetStrings("volume_env") } -func (t T) Capabilities() []string { - return t.GetStrings("capabilities") +func (t T) Capabilities() pool.Capabilities { + l := t.GetStrings("capabilities") + capabilities := make(pool.Capabilities, len(l)) + for i, s := range t.GetStrings("capabilities") { + capabilities[i] = pool.Capability(s) + } + return capabilities } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/poolzpool/main.go b/drivers/poolzpool/main.go index d7c1860bb..d8e9fe03b 100644 --- a/drivers/poolzpool/main.go +++ b/drivers/poolzpool/main.go @@ -44,8 +44,16 @@ func (t T) poolName() string { return t.GetString("name") } -func (t T) Capabilities() []string { - return []string{"rox", "rwx", "roo", "rwo", "snap", "blk"} +func (t T) Capabilities() pool.Capabilities { + return pool.Capabilities{ + pool.CapBlk, + pool.CapFile, + pool.CapROO, + pool.CapROX, + pool.CapRWO, + pool.CapRWX, + pool.CapSnap, + } } func (t T) Usage(ctx context.Context) (pool.Usage, error) { diff --git a/drivers/resvol/main.go b/drivers/resvol/main.go index 040a277ab..b29a6ecbd 100644 --- a/drivers/resvol/main.go +++ b/drivers/resvol/main.go @@ -59,6 +59,7 @@ type ( PoolType string `json:"type"` Size *int64 `json:"size"` Format bool `json:"format"` + Volatile bool `json:"volatile"` VolNodes []string // Context @@ -403,6 +404,7 @@ func (t *T) poolLookup(withUsage bool) (*pool.Lookup, error) { } l.Format = t.Format l.Shared = t.Shared + l.Volatile = t.Volatile l.Access, err = volaccess.Parse(t.Access) if err != nil { return nil, err diff --git a/drivers/resvol/manifest.go b/drivers/resvol/manifest.go index d5bb8b9b4..be84ae69a 100644 --- a/drivers/resvol/manifest.go +++ b/drivers/resvol/manifest.go @@ -45,6 +45,15 @@ func (t *T) Manifest() *manifest.T { Scopable: true, Text: keywords.NewText(fs, "text/kw/type"), }, + keywords.Keyword{ + Attr: "Volatile", + Converter: "bool", + Default: "false", + Option: "volatile", + Provisioning: true, + Scopable: true, + Text: keywords.NewText(fs, "text/kw/volatile"), + }, keywords.Keyword{ Attr: "Access", Candidates: []string{"rwo", "roo", "rwx", "rox"}, diff --git a/drivers/resvol/text/kw/volatile b/drivers/resvol/text/kw/volatile new file mode 100644 index 000000000..c902e2496 --- /dev/null +++ b/drivers/resvol/text/kw/volatile @@ -0,0 +1,2 @@ +Set to true if you want the pool lookup to return a pool creating vol object that discards data on stop. +Temporary files and secret content usually want `volatile=true`.