From dffec7b507cefa8d3948778f7258f4595fb89a74 Mon Sep 17 00:00:00 2001 From: GokceGK Date: Mon, 11 May 2026 09:38:34 +0200 Subject: [PATCH 1/3] feat(sfs): extend resource-pool commands with snapshotPolicyId relates to STACKITCLI-394 --- docs/stackit_beta_sfs_resource-pool_create.md | 18 +++++++++++------- docs/stackit_beta_sfs_resource-pool_update.md | 14 +++++++++----- .../beta/sfs/resource-pool/create/create.go | 9 +++++++++ .../sfs/resource-pool/create/create_test.go | 14 ++++++++++++++ .../sfs/resource-pool/describe/describe.go | 7 +++++++ .../cmd/beta/sfs/resource-pool/list/list.go | 7 ++++++- .../beta/sfs/resource-pool/update/update.go | 9 +++++++++ .../sfs/resource-pool/update/update_test.go | 15 +++++++++++++++ 8 files changed, 80 insertions(+), 13 deletions(-) diff --git a/docs/stackit_beta_sfs_resource-pool_create.md b/docs/stackit_beta_sfs_resource-pool_create.md index 5643e8671..4c0e9ada1 100644 --- a/docs/stackit_beta_sfs_resource-pool_create.md +++ b/docs/stackit_beta_sfs_resource-pool_create.md @@ -27,18 +27,22 @@ stackit beta sfs resource-pool create [flags] Create a SFS resource pool with visible snapshots $ stackit beta sfs resource-pool create --availability-zone eu01-m --ip-acl 10.88.135.144/28 --performance-class Standard --size 500 --name resource-pool-01 --snapshots-visible + + Create a SFS resource pool with specific snapshot policy + $ stackit beta sfs resource-pool create --availability-zone eu01-m --ip-acl 10.88.135.144/28 --performance-class Standard --size 500 --name resource-pool-01 --snapshot-policy-id XXX ``` ### Options ``` - --availability-zone string Availability zone - -h, --help Help for "stackit beta sfs resource-pool create" - --ip-acl strings List of network addresses in the form
, e.g. 192.168.10.0/24 that can mount the resource pool readonly (default []) - --name string Name - --performance-class string Performance class - --size int32 Size of the pool in Gigabytes - --snapshots-visible Set snapshots visible and accessible to users + --availability-zone string Availability zone + -h, --help Help for "stackit beta sfs resource-pool create" + --ip-acl strings List of network addresses in the form
, e.g. 192.168.10.0/24 that can mount the resource pool readonly (default []) + --name string Name + --performance-class string Performance class + --size int32 Size of the pool in Gigabytes + --snapshot-policy-id string Set snapshot policy ID + --snapshots-visible Set snapshots visible and accessible to users ``` ### Options inherited from parent commands diff --git a/docs/stackit_beta_sfs_resource-pool_update.md b/docs/stackit_beta_sfs_resource-pool_update.md index 3929a5e14..ebabd8ec4 100644 --- a/docs/stackit_beta_sfs_resource-pool_update.md +++ b/docs/stackit_beta_sfs_resource-pool_update.md @@ -27,16 +27,20 @@ stackit beta sfs resource-pool update [flags] Update the SFS resource pool with ID "xxx", set snapshots visible to false $ stackit beta sfs resource-pool update xxx --snapshots-visible=false + + Update the SFS resource pool with ID "xxx" to set snapshot policy id to "YYY" + $ stackit beta sfs resource-pool update xxx --snapshot-policy-id=YYY ``` ### Options ``` - -h, --help Help for "stackit beta sfs resource-pool update" - --ip-acl strings List of network addresses in the form
, e.g. 192.168.10.0/24 that can mount the resource pool readonly (default []) - --performance-class string Performance class - --size int32 Size of the pool in Gigabytes - --snapshots-visible Set snapshots visible and accessible to users + -h, --help Help for "stackit beta sfs resource-pool update" + --ip-acl strings List of network addresses in the form
, e.g. 192.168.10.0/24 that can mount the resource pool readonly (default []) + --performance-class string Performance class + --size int32 Size of the pool in Gigabytes + --snapshot-policy-id string Set snapshot policy ID + --snapshots-visible Set snapshots visible and accessible to users ``` ### Options inherited from parent commands diff --git a/internal/cmd/beta/sfs/resource-pool/create/create.go b/internal/cmd/beta/sfs/resource-pool/create/create.go index 47420cbc3..afbb83200 100644 --- a/internal/cmd/beta/sfs/resource-pool/create/create.go +++ b/internal/cmd/beta/sfs/resource-pool/create/create.go @@ -28,6 +28,7 @@ const ( availabilityZoneFlag = "availability-zone" nameFlag = "name" snapshotsVisibleFlag = "snapshots-visible" + snapshotPolicyIdFlag = "snapshot-policy-id" ) type inputModel struct { @@ -38,6 +39,7 @@ type inputModel struct { Name string AvailabilityZone string SnapshotsVisible bool + SnapshotPolicyId string } func NewCmd(params *types.CmdParams) *cobra.Command { @@ -62,6 +64,9 @@ The available performance class values can be obtained by running: examples.NewExample( `Create a SFS resource pool with visible snapshots`, "$ stackit beta sfs resource-pool create --availability-zone eu01-m --ip-acl 10.88.135.144/28 --performance-class Standard --size 500 --name resource-pool-01 --snapshots-visible"), + examples.NewExample( + `Create a SFS resource pool with specific snapshot policy`, + "$ stackit beta sfs resource-pool create --availability-zone eu01-m --ip-acl 10.88.135.144/28 --performance-class Standard --size 500 --name resource-pool-01 --snapshot-policy-id XXX"), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -124,6 +129,7 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().String(availabilityZoneFlag, "", "Availability zone") cmd.Flags().String(nameFlag, "", "Name") cmd.Flags().Bool(snapshotsVisibleFlag, false, "Set snapshots visible and accessible to users") + cmd.Flags().String(snapshotPolicyIdFlag, "", "Set snapshot policy ID") for _, flag := range []string{sizeFlag, performanceClassFlag, ipAclFlag, availabilityZoneFlag, nameFlag} { err := flags.MarkFlagsRequired(cmd, flag) @@ -140,6 +146,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *sfs.APIClie PerformanceClass: model.PerformanceClass, SizeGigabytes: *model.SizeInGB, SnapshotsAreVisible: &model.SnapshotsVisible, + SnapshotPolicyId: &model.SnapshotPolicyId, }) return req } @@ -156,6 +163,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, ipAcls := flags.FlagToStringSliceValue(p, cmd, ipAclFlag) name := flags.FlagToStringValue(p, cmd, nameFlag) snapshotsVisible := flags.FlagToBoolValue(p, cmd, snapshotsVisibleFlag) + snapshotPolicyId := flags.FlagToStringValue(p, cmd, snapshotPolicyIdFlag) model := inputModel{ GlobalFlagModel: globalFlags, @@ -165,6 +173,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, AvailabilityZone: availabilityZone, Name: name, SnapshotsVisible: snapshotsVisible, + SnapshotPolicyId: snapshotPolicyId, } p.DebugInputModel(model) diff --git a/internal/cmd/beta/sfs/resource-pool/create/create_test.go b/internal/cmd/beta/sfs/resource-pool/create/create_test.go index 8dbb653e9..53d47e36f 100644 --- a/internal/cmd/beta/sfs/resource-pool/create/create_test.go +++ b/internal/cmd/beta/sfs/resource-pool/create/create_test.go @@ -31,6 +31,7 @@ var ( testResourcePoolName = "sfs-resource-pool-01" testResourcePoolIpAcl = []string{"10.88.135.144/28", "250.81.87.224/32"} testSnapshotsVisible = true + testSnapshotPolicyId = uuid.NewString() ) func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { @@ -43,6 +44,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st availabilityZoneFlag: testResourcePoolAvailabilityZone, nameFlag: testResourcePoolName, snapshotsVisibleFlag: strconv.FormatBool(testSnapshotsVisible), + snapshotPolicyIdFlag: testSnapshotPolicyId, } for _, mod := range mods { mod(flagValues) @@ -63,6 +65,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { SizeInGB: &testResourcePoolSizeInGB, IpAcl: testResourcePoolIpAcl, SnapshotsVisible: testSnapshotsVisible, + SnapshotPolicyId: testSnapshotPolicyId, } for _, mod := range mods { mod(model) @@ -79,6 +82,7 @@ func fixtureRequest(mods ...func(request *sfs.ApiCreateResourcePoolRequest)) sfs IpAcl: testResourcePoolIpAcl, SizeGigabytes: testResourcePoolSizeInGB, SnapshotsAreVisible: &testSnapshotsVisible, + SnapshotPolicyId: &testSnapshotPolicyId, }) for _, mod := range mods { mod(&request) @@ -211,6 +215,16 @@ func TestParseInput(t *testing.T) { }), isValid: false, }, + { + description: "snapshot policy id missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, snapshotPolicyIdFlag) + }), + expectedModel: fixtureInputModel(func(model *inputModel) { + model.SnapshotPolicyId = "" + }), + isValid: true, + }, } for _, tt := range tests { diff --git a/internal/cmd/beta/sfs/resource-pool/describe/describe.go b/internal/cmd/beta/sfs/resource-pool/describe/describe.go index c3a451fae..d20b45aa5 100644 --- a/internal/cmd/beta/sfs/resource-pool/describe/describe.go +++ b/internal/cmd/beta/sfs/resource-pool/describe/describe.go @@ -111,6 +111,11 @@ func outputResult(p *print.Printer, outputFormat, resourcePoolId, projectLabel s ipAclStr = strings.Join(resourcePool.IpAcl, ", ") } + var snapshotPolicyId string + if resourcePool.SnapshotPolicy.Get() != nil { + snapshotPolicyId = *resourcePool.SnapshotPolicy.Get().Id + } + table.AddRow("ID", utils.PtrString(resourcePool.Id)) table.AddSeparator() table.AddRow("NAME", utils.PtrString(resourcePool.Name)) @@ -129,6 +134,8 @@ func outputResult(p *print.Printer, outputFormat, resourcePoolId, projectLabel s } table.AddRow("SNAPSHOTS ARE VISIBLE", utils.PtrString(resourcePool.SnapshotsAreVisible)) table.AddSeparator() + table.AddRow("SNAPSHOT POLICY ID", snapshotPolicyId) + table.AddSeparator() table.AddRow("NEXT PERFORMANCE CLASS DOWNGRADE TIME", resourcePool.PerformanceClassDowngradableAt) table.AddSeparator() table.AddRow("NEXT SIZE REDUCTION TIME", resourcePool.SizeReducibleAt) diff --git a/internal/cmd/beta/sfs/resource-pool/list/list.go b/internal/cmd/beta/sfs/resource-pool/list/list.go index be46ce2ec..a641f2b3d 100644 --- a/internal/cmd/beta/sfs/resource-pool/list/list.go +++ b/internal/cmd/beta/sfs/resource-pool/list/list.go @@ -128,13 +128,17 @@ func outputResult(p *print.Printer, outputFormat, projectLabel string, resourceP } table := tables.NewTable() - table.SetHeader("ID", "NAME", "AVAILABILITY ZONE", "STATE", "TOTAL SIZE (GB)", "USED SIZE (GB)") + table.SetHeader("ID", "NAME", "AVAILABILITY ZONE", "STATE", "TOTAL SIZE (GB)", "USED SIZE (GB), SNAPSHOT POLICY ID") for _, resourcePool := range resourcePools { totalSizeGigabytes, usedSizeGigabytes := "", "" if resourcePool.HasSpace() { totalSizeGigabytes = utils.PtrString(resourcePool.Space.SizeGigabytes) usedSizeGigabytes = utils.PtrString(resourcePool.Space.UsedGigabytes.Get()) } + var snapshotPolicyId string + if resourcePool.SnapshotPolicy.Get() != nil { + snapshotPolicyId = *resourcePool.SnapshotPolicy.Get().Id + } table.AddRow( utils.PtrString(resourcePool.Id), utils.PtrString(resourcePool.Name), @@ -142,6 +146,7 @@ func outputResult(p *print.Printer, outputFormat, projectLabel string, resourceP utils.PtrString(resourcePool.State), totalSizeGigabytes, usedSizeGigabytes, + snapshotPolicyId, ) } err := table.Display(p) diff --git a/internal/cmd/beta/sfs/resource-pool/update/update.go b/internal/cmd/beta/sfs/resource-pool/update/update.go index 0203c80d8..be705179e 100644 --- a/internal/cmd/beta/sfs/resource-pool/update/update.go +++ b/internal/cmd/beta/sfs/resource-pool/update/update.go @@ -28,6 +28,7 @@ const ( sizeFlag = "size" ipAclFlag = "ip-acl" snapshotsVisibleFlag = "snapshots-visible" + snapshotPolicyIdFlag = "snapshot-policy-id" ) type inputModel struct { @@ -37,6 +38,7 @@ type inputModel struct { IpAcl []string ResourcePoolId string SnapshotsVisible *bool + SnapshotPolicyId *string } func NewCmd(params *types.CmdParams) *cobra.Command { @@ -61,6 +63,9 @@ The available performance class values can be obtained by running: examples.NewExample( `Update the SFS resource pool with ID "xxx", set snapshots visible to false`, "$ stackit beta sfs resource-pool update xxx --snapshots-visible=false"), + examples.NewExample( + `Update the SFS resource pool with ID "xxx" to set snapshot policy id to "YYY"`, + "$ stackit beta sfs resource-pool update xxx --snapshot-policy-id=YYY"), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -123,6 +128,7 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().String(performanceClassFlag, "", "Performance class") cmd.Flags().Var(flags.CIDRSliceFlag(), ipAclFlag, "List of network addresses in the form
, e.g. 192.168.10.0/24 that can mount the resource pool readonly") cmd.Flags().Bool(snapshotsVisibleFlag, false, "Set snapshots visible and accessible to users") + cmd.Flags().String(snapshotPolicyIdFlag, "", "Set snapshot policy ID") } func buildRequest(ctx context.Context, model *inputModel, apiClient *sfs.APIClient) sfs.ApiUpdateResourcePoolRequest { @@ -132,6 +138,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *sfs.APIClie PerformanceClass: model.PerformanceClass, SizeGigabytes: *sfs.NewNullableInt32(model.SizeGigabytes), SnapshotsAreVisible: model.SnapshotsVisible, + SnapshotPolicyId: model.SnapshotPolicyId, }) return req } @@ -148,6 +155,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu size := flags.FlagToInt32Pointer(p, cmd, sizeFlag) ipAcls := flags.FlagToStringSliceValue(p, cmd, ipAclFlag) snapshotsVisible := flags.FlagToBoolPointer(p, cmd, snapshotsVisibleFlag) + snapshotPolicyId := flags.FlagToStringPointer(p, cmd, snapshotPolicyIdFlag) if performanceClass == nil && size == nil && ipAcls == nil && snapshotsVisible == nil { return nil, &cliErr.EmptyUpdateError{} @@ -160,6 +168,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu PerformanceClass: performanceClass, ResourcePoolId: resourcePoolId, SnapshotsVisible: snapshotsVisible, + SnapshotPolicyId: snapshotPolicyId, } p.DebugInputModel(model) diff --git a/internal/cmd/beta/sfs/resource-pool/update/update_test.go b/internal/cmd/beta/sfs/resource-pool/update/update_test.go index 58d2d4c0e..03b103299 100644 --- a/internal/cmd/beta/sfs/resource-pool/update/update_test.go +++ b/internal/cmd/beta/sfs/resource-pool/update/update_test.go @@ -34,6 +34,7 @@ var ( testResourcePoolPerformanceClass = "Standard" testResourcePoolSizeInGB int32 = 50 testSnapshotsVisible = true + testSnapshotPolicyId = uuid.NewString() ) func fixtureArgValues(mods ...func(argValues []string)) []string { @@ -54,6 +55,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st sizeFlag: strconv.FormatInt(int64(testResourcePoolSizeInGB), 10), ipAclFlag: strings.Join(testResourcePoolIpAcl, ","), snapshotsVisibleFlag: strconv.FormatBool(testSnapshotsVisible), + snapshotPolicyIdFlag: testSnapshotPolicyId, } for _, mod := range mods { mod(flagValues) @@ -75,6 +77,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { PerformanceClass: &testResourcePoolPerformanceClass, IpAcl: ipAclClone, SnapshotsVisible: &testSnapshotsVisible, + SnapshotPolicyId: &testSnapshotPolicyId, } for _, mod := range mods { mod(model) @@ -89,6 +92,7 @@ func fixtureRequest(mods ...func(request *sfs.ApiUpdateResourcePoolRequest)) sfs PerformanceClass: &testResourcePoolPerformanceClass, SizeGigabytes: *sfs.NewNullableInt32(&testResourcePoolSizeInGB), SnapshotsAreVisible: &testSnapshotsVisible, + SnapshotPolicyId: &testSnapshotPolicyId, }) for _, mod := range mods { mod(&request) @@ -266,6 +270,17 @@ func TestParseInput(t *testing.T) { model.IpAcl = append(model.IpAcl, "198.51.100.14/24", "198.51.100.14/32") }), }, + { + description: "snapshot policy id missing", + argValues: fixtureArgValues(), + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, snapshotPolicyIdFlag) + }), + expectedModel: fixtureInputModel(func(model *inputModel) { + model.SnapshotPolicyId = nil + }), + isValid: true, + }, } for _, tt := range tests { From 4981d3495171b1263640c697a67543ccf5add3a0 Mon Sep 17 00:00:00 2001 From: GokceGK Date: Mon, 11 May 2026 10:21:57 +0200 Subject: [PATCH 2/3] feat(sfs): extend resource-pool commands with snapshotPolicyId relates to STACKITCLI-394 --- docs/stackit_beta_sfs_resource-pool_update.md | 2 +- internal/cmd/beta/sfs/resource-pool/list/list.go | 7 +------ internal/cmd/beta/sfs/resource-pool/update/update.go | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/stackit_beta_sfs_resource-pool_update.md b/docs/stackit_beta_sfs_resource-pool_update.md index ebabd8ec4..7738e0e5c 100644 --- a/docs/stackit_beta_sfs_resource-pool_update.md +++ b/docs/stackit_beta_sfs_resource-pool_update.md @@ -29,7 +29,7 @@ stackit beta sfs resource-pool update [flags] $ stackit beta sfs resource-pool update xxx --snapshots-visible=false Update the SFS resource pool with ID "xxx" to set snapshot policy id to "YYY" - $ stackit beta sfs resource-pool update xxx --snapshot-policy-id=YYY + $ stackit beta sfs resource-pool update xxx --snapshot-policy-id YYY ``` ### Options diff --git a/internal/cmd/beta/sfs/resource-pool/list/list.go b/internal/cmd/beta/sfs/resource-pool/list/list.go index a641f2b3d..be46ce2ec 100644 --- a/internal/cmd/beta/sfs/resource-pool/list/list.go +++ b/internal/cmd/beta/sfs/resource-pool/list/list.go @@ -128,17 +128,13 @@ func outputResult(p *print.Printer, outputFormat, projectLabel string, resourceP } table := tables.NewTable() - table.SetHeader("ID", "NAME", "AVAILABILITY ZONE", "STATE", "TOTAL SIZE (GB)", "USED SIZE (GB), SNAPSHOT POLICY ID") + table.SetHeader("ID", "NAME", "AVAILABILITY ZONE", "STATE", "TOTAL SIZE (GB)", "USED SIZE (GB)") for _, resourcePool := range resourcePools { totalSizeGigabytes, usedSizeGigabytes := "", "" if resourcePool.HasSpace() { totalSizeGigabytes = utils.PtrString(resourcePool.Space.SizeGigabytes) usedSizeGigabytes = utils.PtrString(resourcePool.Space.UsedGigabytes.Get()) } - var snapshotPolicyId string - if resourcePool.SnapshotPolicy.Get() != nil { - snapshotPolicyId = *resourcePool.SnapshotPolicy.Get().Id - } table.AddRow( utils.PtrString(resourcePool.Id), utils.PtrString(resourcePool.Name), @@ -146,7 +142,6 @@ func outputResult(p *print.Printer, outputFormat, projectLabel string, resourceP utils.PtrString(resourcePool.State), totalSizeGigabytes, usedSizeGigabytes, - snapshotPolicyId, ) } err := table.Display(p) diff --git a/internal/cmd/beta/sfs/resource-pool/update/update.go b/internal/cmd/beta/sfs/resource-pool/update/update.go index be705179e..e22f309b0 100644 --- a/internal/cmd/beta/sfs/resource-pool/update/update.go +++ b/internal/cmd/beta/sfs/resource-pool/update/update.go @@ -65,7 +65,7 @@ The available performance class values can be obtained by running: "$ stackit beta sfs resource-pool update xxx --snapshots-visible=false"), examples.NewExample( `Update the SFS resource pool with ID "xxx" to set snapshot policy id to "YYY"`, - "$ stackit beta sfs resource-pool update xxx --snapshot-policy-id=YYY"), + "$ stackit beta sfs resource-pool update xxx --snapshot-policy-id YYY"), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() From 40eabb932f31216ead0231fce5f16a42f92805b4 Mon Sep 17 00:00:00 2001 From: GokceGK Date: Mon, 11 May 2026 10:44:13 +0200 Subject: [PATCH 3/3] feat(sfs): extend udpate error handling relates to STACKITCLI-394 --- internal/cmd/beta/sfs/resource-pool/update/update.go | 2 +- internal/cmd/beta/sfs/resource-pool/update/update_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/cmd/beta/sfs/resource-pool/update/update.go b/internal/cmd/beta/sfs/resource-pool/update/update.go index e22f309b0..227f79097 100644 --- a/internal/cmd/beta/sfs/resource-pool/update/update.go +++ b/internal/cmd/beta/sfs/resource-pool/update/update.go @@ -157,7 +157,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu snapshotsVisible := flags.FlagToBoolPointer(p, cmd, snapshotsVisibleFlag) snapshotPolicyId := flags.FlagToStringPointer(p, cmd, snapshotPolicyIdFlag) - if performanceClass == nil && size == nil && ipAcls == nil && snapshotsVisible == nil { + if performanceClass == nil && size == nil && ipAcls == nil && snapshotsVisible == nil && snapshotPolicyId == nil { return nil, &cliErr.EmptyUpdateError{} } diff --git a/internal/cmd/beta/sfs/resource-pool/update/update_test.go b/internal/cmd/beta/sfs/resource-pool/update/update_test.go index 03b103299..a5cd7e75e 100644 --- a/internal/cmd/beta/sfs/resource-pool/update/update_test.go +++ b/internal/cmd/beta/sfs/resource-pool/update/update_test.go @@ -142,6 +142,7 @@ func TestParseInput(t *testing.T) { delete(flagValues, ipAclFlag) delete(flagValues, performanceClassFlag) delete(flagValues, snapshotsVisibleFlag) + delete(flagValues, snapshotPolicyIdFlag) }), isValid: false, },