From 277c45efc60889d8107c1bb15fa0d3a456f25027 Mon Sep 17 00:00:00 2001 From: Romain Dupont Date: Thu, 12 Feb 2026 10:01:25 +0000 Subject: [PATCH 1/2] feat: add cloud share to cli --- internal/cmd/cloud_project.go | 1 + internal/cmd/cloud_share.go | 179 ++++++++++ internal/services/cloud/cloud_share.go | 321 ++++++++++++++++++ .../parameter-samples/share-acl-create.json | 5 + .../cloud/parameter-samples/share-create.json | 6 + .../share-snapshot-create.json | 4 + .../services/cloud/templates/cloud_share.tmpl | 29 ++ .../cloud/templates/cloud_share_acl.tmpl | 14 + .../cloud/templates/cloud_share_snapshot.tmpl | 17 + 9 files changed, 576 insertions(+) create mode 100644 internal/cmd/cloud_share.go create mode 100644 internal/services/cloud/cloud_share.go create mode 100644 internal/services/cloud/parameter-samples/share-acl-create.json create mode 100644 internal/services/cloud/parameter-samples/share-create.json create mode 100644 internal/services/cloud/parameter-samples/share-snapshot-create.json create mode 100644 internal/services/cloud/templates/cloud_share.tmpl create mode 100644 internal/services/cloud/templates/cloud_share_acl.tmpl create mode 100644 internal/services/cloud/templates/cloud_share_snapshot.tmpl diff --git a/internal/cmd/cloud_project.go b/internal/cmd/cloud_project.go index e93269b8..620c8893 100644 --- a/internal/cmd/cloud_project.go +++ b/internal/cmd/cloud_project.go @@ -60,6 +60,7 @@ func init() { initCloudStorageS3Command(cloudCmd) initCloudStorageSwiftCommand(cloudCmd) initCloudVolumeCommand(cloudCmd) + initCloudShareCommand(cloudCmd) initCloudRancherCommand(cloudCmd) initCloudReferenceCmd(cloudCmd) initCloudSavingsPlanCommand(cloudCmd) diff --git a/internal/cmd/cloud_share.go b/internal/cmd/cloud_share.go new file mode 100644 index 00000000..70addac4 --- /dev/null +++ b/internal/cmd/cloud_share.go @@ -0,0 +1,179 @@ +// SPDX-FileCopyrightText: 2025 OVH SAS +// +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "github.com/ovh/ovhcloud-cli/internal/assets" + "github.com/ovh/ovhcloud-cli/internal/services/cloud" + "github.com/spf13/cobra" +) + +func initCloudShareCommand(cloudCmd *cobra.Command) { + shareCmd := &cobra.Command{ + Use: "share", + Short: "Manage shares in the given cloud project", + } + shareCmd.PersistentFlags().StringVar(&cloud.CloudProject, "cloud-project", "", "Cloud project ID") + + // Share CRUD commands + shareListCmd := &cobra.Command{ + Use: "list", + Aliases: []string{"ls"}, + Short: "List shares", + Run: cloud.ListCloudShares, + } + shareCmd.AddCommand(withFilterFlag(shareListCmd)) + + shareCmd.AddCommand(&cobra.Command{ + Use: "get ", + Short: "Get a specific share", + Run: cloud.GetShare, + Args: cobra.ExactArgs(1), + }) + + shareEditCmd := &cobra.Command{ + Use: "edit ", + Short: "Edit the given share", + Run: cloud.EditShare, + Args: cobra.ExactArgs(1), + } + shareEditCmd.Flags().StringVar(&cloud.ShareSpec.Description, "description", "", "Share description") + shareEditCmd.Flags().StringVar(&cloud.ShareSpec.Name, "name", "", "Share name") + shareEditCmd.Flags().IntVar(&cloud.ShareSpec.NewSize, "new-size", 0, "New share size (in GB)") + addInteractiveEditorFlag(shareEditCmd) + shareCmd.AddCommand(shareEditCmd) + + shareCmd.AddCommand(getShareCreateCmd()) + + shareCmd.AddCommand(&cobra.Command{ + Use: "delete ", + Short: "Delete the given share", + Run: cloud.DeleteShare, + Args: cobra.ExactArgs(1), + }) + + // Share ACL commands + shareAclCmd := &cobra.Command{ + Use: "acl", + Short: "Manage ACLs of the given share", + } + shareCmd.AddCommand(shareAclCmd) + + shareAclListCmd := &cobra.Command{ + Use: "list ", + Aliases: []string{"ls"}, + Short: "List ACLs of the given share", + Run: cloud.ListShareAcls, + Args: cobra.ExactArgs(1), + } + shareAclCmd.AddCommand(withFilterFlag(shareAclListCmd)) + + shareAclCmd.AddCommand(&cobra.Command{ + Use: "get ", + Short: "Get a specific share ACL", + Run: cloud.GetShareAcl, + Args: cobra.ExactArgs(2), + }) + + shareAclCmd.AddCommand(getShareAclCreateCmd()) + + shareAclCmd.AddCommand(&cobra.Command{ + Use: "delete ", + Short: "Delete the given share ACL", + Run: cloud.DeleteShareAcl, + Args: cobra.ExactArgs(2), + }) + + // Share Snapshot commands + shareSnapshotCmd := &cobra.Command{ + Use: "snapshot", + Short: "Manage snapshots of the given share", + } + shareCmd.AddCommand(shareSnapshotCmd) + + shareSnapshotListCmd := &cobra.Command{ + Use: "list ", + Aliases: []string{"ls"}, + Short: "List snapshots of the given share", + Run: cloud.ListShareSnapshots, + Args: cobra.ExactArgs(1), + } + shareSnapshotCmd.AddCommand(withFilterFlag(shareSnapshotListCmd)) + + shareSnapshotCmd.AddCommand(&cobra.Command{ + Use: "get ", + Short: "Get a specific share snapshot", + Run: cloud.GetShareSnapshot, + Args: cobra.ExactArgs(2), + }) + + shareSnapshotCmd.AddCommand(getShareSnapshotCreateCmd()) + + shareSnapshotCmd.AddCommand(&cobra.Command{ + Use: "delete ", + Short: "Delete the given share snapshot", + Run: cloud.DeleteShareSnapshot, + Args: cobra.ExactArgs(2), + }) + + cloudCmd.AddCommand(shareCmd) +} + +func getShareCreateCmd() *cobra.Command { + shareCreateCmd := &cobra.Command{ + Use: "create ", + Short: "Create a new share", + Run: cloud.CreateShare, + Args: cobra.ExactArgs(1), + } + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Description, "description", "", "Share description") + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Name, "name", "", "Share name") + shareCreateCmd.Flags().IntVar(&cloud.ShareSpec.Size, "size", 0, "Share size (in GB)") + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Type, "type", "", "Share type (default)") + + addInitParameterFileFlag(shareCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share", "post", cloud.ShareCreateExample, nil) + addInteractiveEditorFlag(shareCreateCmd) + addFromFileFlag(shareCreateCmd) + shareCreateCmd.MarkFlagsMutuallyExclusive("from-file", "editor") + + return shareCreateCmd +} + +func getShareAclCreateCmd() *cobra.Command { + shareAclCreateCmd := &cobra.Command{ + Use: "create ", + Short: "Create a new ACL for the given share", + Run: cloud.CreateShareAcl, + Args: cobra.ExactArgs(1), + } + shareAclCreateCmd.Flags().StringVar(&cloud.ShareAclSpec.AccessType, "access-type", "", "Access type (cert, ip, user)") + shareAclCreateCmd.Flags().StringVar(&cloud.ShareAclSpec.AccessTo, "access-to", "", "Access to (e.g., IP address or CIDR)") + shareAclCreateCmd.Flags().StringVar(&cloud.ShareAclSpec.AccessLevel, "access-level", "", "Access level (ro, rw)") + + addInitParameterFileFlag(shareAclCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share/{id}/acl", "post", cloud.ShareAclCreateExample, nil) + addInteractiveEditorFlag(shareAclCreateCmd) + addFromFileFlag(shareAclCreateCmd) + shareAclCreateCmd.MarkFlagsMutuallyExclusive("from-file", "editor") + + return shareAclCreateCmd +} + +func getShareSnapshotCreateCmd() *cobra.Command { + shareSnapshotCreateCmd := &cobra.Command{ + Use: "create ", + Short: "Create a snapshot of the given share", + Run: cloud.CreateShareSnapshot, + Args: cobra.ExactArgs(1), + } + shareSnapshotCreateCmd.Flags().StringVar(&cloud.ShareSnapshotSpec.Description, "description", "", "Snapshot description") + shareSnapshotCreateCmd.Flags().StringVar(&cloud.ShareSnapshotSpec.Name, "name", "", "Snapshot name") + + addInitParameterFileFlag(shareSnapshotCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share/{id}/snapshot", "post", cloud.ShareSnapshotCreateExample, nil) + addInteractiveEditorFlag(shareSnapshotCreateCmd) + addFromFileFlag(shareSnapshotCreateCmd) + shareSnapshotCreateCmd.MarkFlagsMutuallyExclusive("from-file", "editor") + + return shareSnapshotCreateCmd +} diff --git a/internal/services/cloud/cloud_share.go b/internal/services/cloud/cloud_share.go new file mode 100644 index 00000000..d28a5350 --- /dev/null +++ b/internal/services/cloud/cloud_share.go @@ -0,0 +1,321 @@ +// SPDX-FileCopyrightText: 2025 OVH SAS +// +// SPDX-License-Identifier: Apache-2.0 + +package cloud + +import ( + _ "embed" + "errors" + "fmt" + "net/url" + + "github.com/ovh/ovhcloud-cli/internal/assets" + "github.com/ovh/ovhcloud-cli/internal/display" + filtersLib "github.com/ovh/ovhcloud-cli/internal/filters" + "github.com/ovh/ovhcloud-cli/internal/flags" + httpLib "github.com/ovh/ovhcloud-cli/internal/http" + "github.com/ovh/ovhcloud-cli/internal/services/common" + "github.com/spf13/cobra" +) + +var ( + shareColumnsToDisplay = []string{"id", "name", "region", "protocol", "type", "status", "size"} + + //go:embed templates/cloud_share.tmpl + shareTemplate string + + //go:embed templates/cloud_share_acl.tmpl + shareAclTemplate string + + //go:embed templates/cloud_share_snapshot.tmpl + shareSnapshotTemplate string + + //go:embed parameter-samples/share-create.json + ShareCreateExample string + + //go:embed parameter-samples/share-acl-create.json + ShareAclCreateExample string + + //go:embed parameter-samples/share-snapshot-create.json + ShareSnapshotCreateExample string + + ShareSpec struct { + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + NewSize int `json:"newSize,omitempty"` + Size int `json:"size,omitempty"` + Type string `json:"type,omitempty"` + } + + ShareAclSpec struct { + AccessLevel string `json:"accessLevel,omitempty"` + AccessTo string `json:"accessTo,omitempty"` + AccessType string `json:"accessType,omitempty"` + } + + ShareSnapshotSpec struct { + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + } +) + +// Share CRUD operations + +func ListCloudShares(_ *cobra.Command, _ []string) { + projectID, err := getConfiguredCloudProject() + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + // Fetch regions with share feature available + regions, err := getCloudRegionsWithFeatureAvailable(projectID, "share") + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "failed to fetch regions with share feature available: %s", err) + return + } + + // Fetch shares in all regions + endpoint := fmt.Sprintf("/v1/cloud/project/%s/region", projectID) + shares, err := httpLib.FetchObjectsParallel[[]map[string]any](endpoint+"/%s/share", regions, true) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "failed to fetch shares: %s", err) + return + } + + // Flatten shares in a single array + var allShares []map[string]any + for _, regionShares := range shares { + allShares = append(allShares, regionShares...) + } + + // Filter results + allShares, err = filtersLib.FilterLines(allShares, flags.GenericFilters) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "failed to filter results: %s", err) + return + } + + display.RenderTable(allShares, shareColumnsToDisplay, &flags.OutputFormatConfig) +} + +func findShare(shareId string) (string, map[string]any, error) { + projectID, err := getConfiguredCloudProject() + if err != nil { + return "", nil, err + } + + // Fetch regions with share feature available + regions, err := getCloudRegionsWithFeatureAvailable(projectID, "share") + if err != nil { + return "", nil, fmt.Errorf("failed to fetch regions with share feature available: %s", err) + } + + // Search for the given share in all regions + for _, region := range regions { + var ( + share map[string]any + endpoint = fmt.Sprintf("/v1/cloud/project/%s/region/%s/share/%s", + projectID, url.PathEscape(region.(string)), url.PathEscape(shareId)) + ) + if err := httpLib.Client.Get(endpoint, &share); err == nil { + return endpoint, share, nil + } + } + + return "", nil, errors.New("no share found with given ID") +} + +func GetShare(_ *cobra.Command, args []string) { + _, share, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + display.OutputObject(share, args[0], shareTemplate, &flags.OutputFormatConfig) +} + +func CreateShare(cmd *cobra.Command, args []string) { + projectID, err := getConfiguredCloudProject() + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + endpoint := fmt.Sprintf("/v1/cloud/project/%s/region/%s/share", projectID, url.PathEscape(args[0])) + task, err := common.CreateResource( + cmd, + "/cloud/project/{serviceName}/region/{regionName}/share", + endpoint, + ShareCreateExample, + ShareSpec, + assets.CloudOpenapiSchema, + []string{"name", "size", "type"}, + ) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + display.OutputInfo(&flags.OutputFormatConfig, task, "✅ Share %s created successfully", task["id"]) +} + +func EditShare(cmd *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + if err := common.EditResource( + cmd, + "/cloud/project/{serviceName}/region/{regionName}/share/{id}", + endpoint, + ShareSpec, + assets.CloudOpenapiSchema, + ); err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } +} + +func DeleteShare(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + if err := httpLib.Client.Delete(endpoint, nil); err != nil { + display.OutputError(&flags.OutputFormatConfig, "failed to delete share: %s", err) + return + } + + display.OutputInfo(&flags.OutputFormatConfig, nil, "✅ Share %s deleted successfully", args[0]) +} + +// Share ACL operations + +func ListShareAcls(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + common.ManageListRequestNoExpand(endpoint+"/acl", []string{"id", "accessType", "accessTo", "accessLevel", "status"}, flags.GenericFilters) +} + +func GetShareAcl(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + common.ManageObjectRequest(endpoint+"/acl", args[1], shareAclTemplate) +} + +func CreateShareAcl(cmd *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + acl, err := common.CreateResource( + cmd, + "/cloud/project/{serviceName}/region/{regionName}/share/{id}/acl", + endpoint+"/acl", + ShareAclCreateExample, + ShareAclSpec, + assets.CloudOpenapiSchema, + []string{"accessType", "accessTo", "accessLevel"}, + ) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + display.OutputInfo(&flags.OutputFormatConfig, acl, "✅ Share ACL %s created successfully", acl["id"]) +} + +func DeleteShareAcl(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + aclEndpoint := fmt.Sprintf("%s/acl/%s", endpoint, url.PathEscape(args[1])) + if err := httpLib.Client.Delete(aclEndpoint, nil); err != nil { + display.OutputError(&flags.OutputFormatConfig, "failed to delete share ACL: %s", err) + return + } + + display.OutputInfo(&flags.OutputFormatConfig, nil, "✅ Share ACL %s deleted successfully", args[1]) +} + +// Share Snapshot operations + +func ListShareSnapshots(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + common.ManageListRequestNoExpand(endpoint+"/snapshot", []string{"id", "name", "shareId", "status", "size"}, flags.GenericFilters) +} + +func GetShareSnapshot(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + common.ManageObjectRequest(endpoint+"/snapshot", args[1], shareSnapshotTemplate) +} + +func CreateShareSnapshot(cmd *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + snapshot, err := common.CreateResource( + cmd, + "/cloud/project/{serviceName}/region/{regionName}/share/{id}/snapshot", + endpoint+"/snapshot", + ShareSnapshotCreateExample, + ShareSnapshotSpec, + assets.CloudOpenapiSchema, + []string{}, + ) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + display.OutputInfo(&flags.OutputFormatConfig, snapshot, "✅ Share snapshot %s created successfully", snapshot["id"]) +} + +func DeleteShareSnapshot(_ *cobra.Command, args []string) { + endpoint, _, err := findShare(args[0]) + if err != nil { + display.OutputError(&flags.OutputFormatConfig, "%s", err) + return + } + + snapshotEndpoint := fmt.Sprintf("%s/snapshot/%s", endpoint, url.PathEscape(args[1])) + if err := httpLib.Client.Delete(snapshotEndpoint, nil); err != nil { + display.OutputError(&flags.OutputFormatConfig, "failed to delete share snapshot: %s", err) + return + } + + display.OutputInfo(&flags.OutputFormatConfig, nil, "✅ Share snapshot %s deleted successfully", args[1]) +} diff --git a/internal/services/cloud/parameter-samples/share-acl-create.json b/internal/services/cloud/parameter-samples/share-acl-create.json new file mode 100644 index 00000000..a5da905f --- /dev/null +++ b/internal/services/cloud/parameter-samples/share-acl-create.json @@ -0,0 +1,5 @@ +{ + "accessType": "ip", + "accessTo": "192.168.1.0/24", + "accessLevel": "rw" +} \ No newline at end of file diff --git a/internal/services/cloud/parameter-samples/share-create.json b/internal/services/cloud/parameter-samples/share-create.json new file mode 100644 index 00000000..8328d2a7 --- /dev/null +++ b/internal/services/cloud/parameter-samples/share-create.json @@ -0,0 +1,6 @@ +{ + "name": "myshare", + "description": "My shared storage", + "size": 100, + "type": "default" +} \ No newline at end of file diff --git a/internal/services/cloud/parameter-samples/share-snapshot-create.json b/internal/services/cloud/parameter-samples/share-snapshot-create.json new file mode 100644 index 00000000..5648f9b9 --- /dev/null +++ b/internal/services/cloud/parameter-samples/share-snapshot-create.json @@ -0,0 +1,4 @@ +{ + "name": "myshare-snapshot", + "description": "Snapshot of my shared storage" +} \ No newline at end of file diff --git a/internal/services/cloud/templates/cloud_share.tmpl b/internal/services/cloud/templates/cloud_share.tmpl new file mode 100644 index 00000000..74e57b25 --- /dev/null +++ b/internal/services/cloud/templates/cloud_share.tmpl @@ -0,0 +1,29 @@ +🚀 Share {{.ServiceName}} +======= + +_{{index .Result "description"}}_ + +## General information + +**Name**: {{index .Result "name"}} +**ID**: {{index .Result "id"}} +**Region**: {{index .Result "region"}} +**Type**: {{index .Result "type"}} +**Protocol**: {{index .Result "protocol"}} +**Status**: {{index .Result "status"}} +**Size**: {{index .Result "size"}}GB +**Public**: {{index .Result "isPublic"}} +**Created at**: {{index .Result "createdAt"}} +**Updated at**: {{index .Result "updatedAt"}} + +## Export locations +{{range index .Result "exportLocations"}} +- **ID**: {{.id}}, **Path**: {{.path}} +{{end}} + +## Capabilities +{{range index .Result "capabilities"}} +- {{.name}}: {{.enabled}} +{{end}} + +💡 Use option --json or --yaml to get the raw output with all information diff --git a/internal/services/cloud/templates/cloud_share_acl.tmpl b/internal/services/cloud/templates/cloud_share_acl.tmpl new file mode 100644 index 00000000..a6c21da1 --- /dev/null +++ b/internal/services/cloud/templates/cloud_share_acl.tmpl @@ -0,0 +1,14 @@ +🔐 Share ACL {{.ServiceName}} +======= + +## General information + +**ID**: {{index .Result "id"}} +**Access Type**: {{index .Result "accessType"}} +**Access To**: {{index .Result "accessTo"}} +**Access Level**: {{index .Result "accessLevel"}} +**Status**: {{index .Result "status"}} +**Created at**: {{index .Result "createdAt"}} +**Updated at**: {{index .Result "updatedAt"}} + +💡 Use option --json or --yaml to get the raw output with all information diff --git a/internal/services/cloud/templates/cloud_share_snapshot.tmpl b/internal/services/cloud/templates/cloud_share_snapshot.tmpl new file mode 100644 index 00000000..db69095a --- /dev/null +++ b/internal/services/cloud/templates/cloud_share_snapshot.tmpl @@ -0,0 +1,17 @@ +📸 Share Snapshot {{.ServiceName}} +======= + +_{{index .Result "description"}}_ + +## General information + +**Name**: {{index .Result "name"}} +**ID**: {{index .Result "id"}} +**Share ID**: {{index .Result "shareId"}} +**Share Protocol**: {{index .Result "shareProtocol"}} +**Status**: {{index .Result "status"}} +**Size**: {{index .Result "size"}}GB +**Share Size**: {{index .Result "shareSize"}}GB +**Created at**: {{index .Result "createdAt"}} + +💡 Use option --json or --yaml to get the raw output with all information From 059df076c0daacb267bbc3cdb9a08698a7f3db1e Mon Sep 17 00:00:00 2001 From: Romain Dupont Date: Mon, 23 Feb 2026 13:14:00 +0000 Subject: [PATCH 2/2] feat: add share Signed-off-by: Romain Dupont --- internal/cmd/cloud_share.go | 10 ++++++---- internal/services/cloud/cloud_share.go | 12 +++++++----- .../cloud/parameter-samples/share-acl-create.json | 1 - .../cloud/parameter-samples/share-create.json | 4 +++- internal/services/cloud/templates/cloud_share.tmpl | 4 +++- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/internal/cmd/cloud_share.go b/internal/cmd/cloud_share.go index 70addac4..475eb062 100644 --- a/internal/cmd/cloud_share.go +++ b/internal/cmd/cloud_share.go @@ -130,8 +130,11 @@ func getShareCreateCmd() *cobra.Command { } shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Description, "description", "", "Share description") shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Name, "name", "", "Share name") + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.NetworkId, "network-id", "", "Network ID") shareCreateCmd.Flags().IntVar(&cloud.ShareSpec.Size, "size", 0, "Share size (in GB)") - shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Type, "type", "", "Share type (default)") + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.SnapshotId, "snapshot-id", "", "Snapshot ID to create the share from") + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.SubnetId, "subnet-id", "", "Subnet ID") + shareCreateCmd.Flags().StringVar(&cloud.ShareSpec.Type, "type", "", "Share type (standard-1az)") addInitParameterFileFlag(shareCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share", "post", cloud.ShareCreateExample, nil) addInteractiveEditorFlag(shareCreateCmd) @@ -148,11 +151,10 @@ func getShareAclCreateCmd() *cobra.Command { Run: cloud.CreateShareAcl, Args: cobra.ExactArgs(1), } - shareAclCreateCmd.Flags().StringVar(&cloud.ShareAclSpec.AccessType, "access-type", "", "Access type (cert, ip, user)") shareAclCreateCmd.Flags().StringVar(&cloud.ShareAclSpec.AccessTo, "access-to", "", "Access to (e.g., IP address or CIDR)") shareAclCreateCmd.Flags().StringVar(&cloud.ShareAclSpec.AccessLevel, "access-level", "", "Access level (ro, rw)") - addInitParameterFileFlag(shareAclCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share/{id}/acl", "post", cloud.ShareAclCreateExample, nil) + addInitParameterFileFlag(shareAclCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share/{shareId}/acl", "post", cloud.ShareAclCreateExample, nil) addInteractiveEditorFlag(shareAclCreateCmd) addFromFileFlag(shareAclCreateCmd) shareAclCreateCmd.MarkFlagsMutuallyExclusive("from-file", "editor") @@ -170,7 +172,7 @@ func getShareSnapshotCreateCmd() *cobra.Command { shareSnapshotCreateCmd.Flags().StringVar(&cloud.ShareSnapshotSpec.Description, "description", "", "Snapshot description") shareSnapshotCreateCmd.Flags().StringVar(&cloud.ShareSnapshotSpec.Name, "name", "", "Snapshot name") - addInitParameterFileFlag(shareSnapshotCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share/{id}/snapshot", "post", cloud.ShareSnapshotCreateExample, nil) + addInitParameterFileFlag(shareSnapshotCreateCmd, assets.CloudOpenapiSchema, "/cloud/project/{serviceName}/region/{regionName}/share/{shareId}/snapshot", "post", cloud.ShareSnapshotCreateExample, nil) addInteractiveEditorFlag(shareSnapshotCreateCmd) addFromFileFlag(shareSnapshotCreateCmd) shareSnapshotCreateCmd.MarkFlagsMutuallyExclusive("from-file", "editor") diff --git a/internal/services/cloud/cloud_share.go b/internal/services/cloud/cloud_share.go index d28a5350..4df10c55 100644 --- a/internal/services/cloud/cloud_share.go +++ b/internal/services/cloud/cloud_share.go @@ -43,15 +43,17 @@ var ( ShareSpec struct { Description string `json:"description,omitempty"` Name string `json:"name,omitempty"` + NetworkId string `json:"networkId,omitempty"` NewSize int `json:"newSize,omitempty"` Size int `json:"size,omitempty"` + SnapshotId string `json:"snapshotId,omitempty"` + SubnetId string `json:"subnetId,omitempty"` Type string `json:"type,omitempty"` } ShareAclSpec struct { AccessLevel string `json:"accessLevel,omitempty"` AccessTo string `json:"accessTo,omitempty"` - AccessType string `json:"accessType,omitempty"` } ShareSnapshotSpec struct { @@ -171,7 +173,7 @@ func EditShare(cmd *cobra.Command, args []string) { if err := common.EditResource( cmd, - "/cloud/project/{serviceName}/region/{regionName}/share/{id}", + "/cloud/project/{serviceName}/region/{regionName}/share/{shareId}", endpoint, ShareSpec, assets.CloudOpenapiSchema, @@ -227,12 +229,12 @@ func CreateShareAcl(cmd *cobra.Command, args []string) { acl, err := common.CreateResource( cmd, - "/cloud/project/{serviceName}/region/{regionName}/share/{id}/acl", + "/cloud/project/{serviceName}/region/{regionName}/share/{shareId}/acl", endpoint+"/acl", ShareAclCreateExample, ShareAclSpec, assets.CloudOpenapiSchema, - []string{"accessType", "accessTo", "accessLevel"}, + []string{"accessTo", "accessLevel"}, ) if err != nil { display.OutputError(&flags.OutputFormatConfig, "%s", err) @@ -289,7 +291,7 @@ func CreateShareSnapshot(cmd *cobra.Command, args []string) { snapshot, err := common.CreateResource( cmd, - "/cloud/project/{serviceName}/region/{regionName}/share/{id}/snapshot", + "/cloud/project/{serviceName}/region/{regionName}/share/{shareId}/snapshot", endpoint+"/snapshot", ShareSnapshotCreateExample, ShareSnapshotSpec, diff --git a/internal/services/cloud/parameter-samples/share-acl-create.json b/internal/services/cloud/parameter-samples/share-acl-create.json index a5da905f..048e4256 100644 --- a/internal/services/cloud/parameter-samples/share-acl-create.json +++ b/internal/services/cloud/parameter-samples/share-acl-create.json @@ -1,5 +1,4 @@ { - "accessType": "ip", "accessTo": "192.168.1.0/24", "accessLevel": "rw" } \ No newline at end of file diff --git a/internal/services/cloud/parameter-samples/share-create.json b/internal/services/cloud/parameter-samples/share-create.json index 8328d2a7..4da340fc 100644 --- a/internal/services/cloud/parameter-samples/share-create.json +++ b/internal/services/cloud/parameter-samples/share-create.json @@ -1,6 +1,8 @@ { "name": "myshare", "description": "My shared storage", + "networkId": "00000000-0000-0000-0000-000000000000", "size": 100, - "type": "default" + "subnetId": "00000000-0000-0000-0000-000000000000", + "type": "standard-1az" } \ No newline at end of file diff --git a/internal/services/cloud/templates/cloud_share.tmpl b/internal/services/cloud/templates/cloud_share.tmpl index 74e57b25..fa38b460 100644 --- a/internal/services/cloud/templates/cloud_share.tmpl +++ b/internal/services/cloud/templates/cloud_share.tmpl @@ -13,8 +13,10 @@ _{{index .Result "description"}}_ **Status**: {{index .Result "status"}} **Size**: {{index .Result "size"}}GB **Public**: {{index .Result "isPublic"}} +**Network ID**: {{index .Result "networkId"}} +**Share Network ID**: {{index .Result "shareNetworkId"}} +**Subnet ID**: {{index .Result "subnetId"}} **Created at**: {{index .Result "createdAt"}} -**Updated at**: {{index .Result "updatedAt"}} ## Export locations {{range index .Result "exportLocations"}}