Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: volume qos list #290

Merged
merged 13 commits into from
May 10, 2024
34 changes: 33 additions & 1 deletion cmd/completion/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,38 @@ func (c *Completion) PartitionListCompletion(cmd *cobra.Command, args []string,
return sc.Payload.Partitions, cobra.ShellCompDirectiveNoFileComp
}

func (c *Completion) PolicyIDListCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
request := volume.NewListPoliciesParams()
sc, err := c.cloud.Volume.ListPolicies(request, nil)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
policyids := make([]string, 0, len(sc.Payload))
for _, policy := range sc.Payload {
if policy.QoSPolicyID == nil {
continue
}
policyids = append(policyids, *policy.QoSPolicyID)
}
return policyids, cobra.ShellCompDirectiveNoFileComp
}

func (c *Completion) PolicyNameListCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
request := volume.NewListPoliciesParams()
sc, err := c.cloud.Volume.ListPolicies(request, nil)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
policyNames := make([]string, 0, len(sc.Payload))
for _, policy := range sc.Payload {
if policy.Name == nil {
continue
}
policyNames = append(policyNames, *policy.Name)
}
return policyNames, cobra.ShellCompDirectiveNoFileComp
}

func (c *Completion) SeedListCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
request := cluster.NewListConstraintsParams()
sc, err := c.cloud.Cluster.ListConstraints(request, nil)
Expand Down Expand Up @@ -199,7 +231,7 @@ func (c *Completion) VolumeListCompletion(cmd *cobra.Command, args []string, toC
if v.VolumeID == nil {
continue
}
names = append(names, *v.VolumeID)
names = append(names, *v.VolumeID+"\t"+pointer.SafeDeref(v.VolumeName))
}
sort.Strings(names)
return names, cobra.ShellCompDirectiveDefault
Expand Down
4 changes: 2 additions & 2 deletions cmd/output/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,7 @@ func (p PostgresBackupEntryTablePrinter) Order(data []*models.V1PostgresBackupEn
}
}

// Order cluster
// Order volume
func (s VolumeTablePrinter) Order(data []*models.V1VolumeResponse) {
cols := strings.Split(s.order, ",")
if len(cols) > 0 {
Expand Down Expand Up @@ -1326,7 +1326,7 @@ func (s VolumeTablePrinter) Order(data []*models.V1VolumeResponse) {
}
}

// Order cluster
// Order snapshot
func (s SnapshotTablePrinter) Order(data []*models.V1SnapshotResponse) {
cols := strings.Split(s.order, ",")
if len(cols) > 0 {
Expand Down
4 changes: 4 additions & 0 deletions cmd/output/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ func (t tablePrinter) Print(data interface{}) error {
SnapshotTablePrinter{t}.Print(d)
case *models.V1SnapshotResponse:
SnapshotTablePrinter{t}.Print(pointer.WrapInSlice(d))
case []*models.V1QoSPolicyResponse:
QoSPolicyTablePrinter{t}.Print(d)
case *models.V1QoSPolicyResponse:
QoSPolicyTablePrinter{t}.Print(pointer.WrapInSlice(d))
case []*models.V1StorageClusterInfo:
VolumeClusterInfoTablePrinter{t}.Print(d)
case models.V1PostgresPartitionsResponse:
Expand Down
82 changes: 79 additions & 3 deletions cmd/output/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/dustin/go-humanize"
"github.com/fi-ts/cloud-go/api/models"
"github.com/fi-ts/cloudctl/cmd/helper"
"github.com/metal-stack/metal-lib/pkg/genericcli"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8syaml "sigs.k8s.io/yaml"
Expand All @@ -23,11 +24,14 @@ type (
SnapshotTablePrinter struct {
tablePrinter
}
QoSPolicyTablePrinter struct {
tablePrinter
}
)

// Print an volume as table
// Print a volume as table
func (p VolumeTablePrinter) Print(data []*models.V1VolumeResponse) {
p.shortHeader = []string{"ID", "Name", "Size", "Usage", "Replicas", "StorageClass", "Project", "Tenant", "Partition"}
p.shortHeader = []string{"ID", "Name", "Size", "Usage", "Replicas", "QoS", "StorageClass", "Project", "Tenant", "Partition"}
p.wideHeader = append(p.shortHeader, "Nodes")
p.Order(data)

Expand All @@ -52,6 +56,12 @@ func (p VolumeTablePrinter) Print(data []*models.V1VolumeResponse) {
if vol.ReplicaCount != nil {
replica = fmt.Sprintf("%d", *vol.ReplicaCount)
}
qos := ""
if vol.QosPolicyName != nil {
qos = *vol.QosPolicyName
} else if vol.QosPolicyUUID != nil {
qos = *vol.QosPolicyUUID
}
sc := ""
if vol.StorageClass != nil {
sc = *vol.StorageClass
Expand All @@ -71,7 +81,7 @@ func (p VolumeTablePrinter) Print(data []*models.V1VolumeResponse) {

nodes := ConnectedHosts(vol)

short := []string{volumeID, name, size, usage, replica, sc, project, tenant, partition}
short := []string{volumeID, name, size, usage, replica, qos, sc, project, tenant, partition}
wide := append(short, strings.Join(nodes, "\n"))

p.addWideData(wide, vol)
Expand Down Expand Up @@ -301,3 +311,69 @@ func (p VolumeClusterInfoTablePrinter) Print(data []*models.V1StorageClusterInfo
}
p.render()
}

// Print a QoS Policy as table
func (p QoSPolicyTablePrinter) Print(data []*models.V1QoSPolicyResponse) {
p.shortHeader = []string{"ID", "Name", "Partition", "Description", "State", "Read", "Write"}
p.wideHeader = p.shortHeader

for _, qos := range data {
id := ""
if qos.QoSPolicyID != nil {
id = *qos.QoSPolicyID
}
name := ""
if qos.Name != nil {
name = *qos.Name
}
partition := ""
if qos.Partition != nil {
partition = *qos.Partition
}
description := ""
longDescription := ""
if qos.Description != nil {
longDescription = *qos.Description
description = genericcli.TruncateEnd(*qos.Description, 40)
}
state := ""
if qos.State != nil {
state = *qos.State
}
read := ""
write := ""
if qos.Limit != nil {
if l := qos.Limit.Bandwidth; l != nil {
if l.Read != nil {
read = fmt.Sprintf("%d MB/s", *l.Read)
}
if l.Write != nil {
write = fmt.Sprintf("%d MB/s", *l.Write)
}
}
if l := qos.Limit.IOPS; l != nil {
if l.Read != nil {
read = fmt.Sprintf("%d IOPS", *l.Read)
}
if l.Write != nil {
write = fmt.Sprintf("%d IOPS", *l.Write)
}
}
if l := qos.Limit.IOPSPerGB; l != nil {
if l.Read != nil {
read = fmt.Sprintf("%d IOPS/GB", *l.Read)
}
if l.Write != nil {
write = fmt.Sprintf("%d IOPS/GB", *l.Write)
}
}
}

short := []string{id, name, partition, description, state, read, write}
wide := []string{id, name, partition, longDescription, state, read, write}

p.addWideData(wide, wide)
p.addShortData(short, qos)
}
p.render()
}
71 changes: 71 additions & 0 deletions cmd/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/fi-ts/cloud-go/api/client/volume"
"github.com/metal-stack/metal-lib/pkg/genericcli"
"github.com/metal-stack/metal-lib/pkg/pointer"

"github.com/fi-ts/cloud-go/api/models"
"github.com/fi-ts/cloudctl/cmd/helper"
Expand Down Expand Up @@ -44,6 +45,15 @@ func newVolumeCmd(c *config) *cobra.Command {
},
ValidArgsFunction: c.comp.VolumeListCompletion,
}
volumeSetQoSCmd := &cobra.Command{
Use: "set-qos <volume>",
Aliases: []string{"set-qos"},
Short: "sets the qos policy of the volume",
RunE: func(cmd *cobra.Command, args []string) error {
return c.volumeSetQoS(args)
},
ValidArgsFunction: c.comp.VolumeListCompletion,
}
volumeManifestCmd := &cobra.Command{
Use: "manifest <volume>",
Short: "print a manifest for a volume",
Expand Down Expand Up @@ -98,6 +108,20 @@ func newVolumeCmd(c *config) *cobra.Command {
},
}

qosCmd := &cobra.Command{
Use: "qos",
Short: "manage qos policies",
Long: "list qos policies",
}
qosListCmd := &cobra.Command{
Use: "list",
Short: "list qos policies",
Aliases: []string{"ls"},
RunE: func(cmd *cobra.Command, args []string) error {
return c.listQoSPolicies()
},
}

snapshotListCmd.Flags().StringP("snapshotid", "", "", "snapshotid to filter [optional]")
snapshotListCmd.Flags().StringP("project", "", "", "project to filter")
snapshotListCmd.Flags().StringP("name", "", "", "name to filter")
Expand All @@ -118,12 +142,16 @@ func newVolumeCmd(c *config) *cobra.Command {
snapshotCmd.AddCommand(snapshotDeleteCmd)
volumeCmd.AddCommand(snapshotCmd)

qosCmd.AddCommand(qosListCmd)
volumeCmd.AddCommand(qosCmd)

volumeCmd.AddCommand(volumeListCmd)
volumeCmd.AddCommand(volumeDeleteCmd)
volumeCmd.AddCommand(volumeDescribeCmd)
volumeCmd.AddCommand(volumeManifestCmd)
volumeCmd.AddCommand(volumeEncryptionSecretManifestCmd)
volumeCmd.AddCommand(volumeClusterInfoCmd)
volumeCmd.AddCommand(volumeSetQoSCmd)

volumeListCmd.Flags().StringP("volumeid", "", "", "volumeid to filter [optional]")
volumeListCmd.Flags().StringP("project", "", "", "project to filter [optional]")
Expand All @@ -144,6 +172,12 @@ func newVolumeCmd(c *config) *cobra.Command {
volumeClusterInfoCmd.Flags().StringP("partition", "", "", "partition to filter [optional]")
genericcli.Must(volumeClusterInfoCmd.RegisterFlagCompletionFunc("partition", c.comp.PartitionListCompletion))

volumeSetQoSCmd.Flags().StringP("qos-id", "", "", "the id of the new qos policy of the volume")
volumeSetQoSCmd.Flags().StringP("qos-name", "", "", "the name of the new qos policy of the volume")

genericcli.Must(volumeSetQoSCmd.RegisterFlagCompletionFunc("qos-id", c.comp.PolicyIDListCompletion))
genericcli.Must(volumeSetQoSCmd.RegisterFlagCompletionFunc("qos-name", c.comp.PolicyNameListCompletion))

return volumeCmd
}

Expand Down Expand Up @@ -226,6 +260,35 @@ If used in cronjob for example, volume might not be connected now, but required
return output.New().Print(resp.Payload)
}

func (c *config) volumeSetQoS(args []string) error {
id, err := genericcli.GetExactlyOneArg(args)
if err != nil {
return err
}
policyId := helper.ViperString("qos-id")
policyName := helper.ViperString("qos-name")

if pointer.SafeDeref(policyId) == "" && pointer.SafeDeref(policyName) == "" {
return fmt.Errorf("either qos-id or qos-name must be specified")
}
if pointer.SafeDeref(policyId) != "" && pointer.SafeDeref(policyName) != "" {
return fmt.Errorf("either qos-id or qos-name must be specified, not both")
}

params := volume.NewSetVolumeQoSPolicyParams().
WithID(id).
WithBody(&models.V1VolumeSetQoSPolicyRequest{
QoSPolicyID: policyId,
QoSPolicyName: policyName,
})

resp, err := c.cloud.Volume.SetVolumeQoSPolicy(params, nil)
if err != nil {
return err
}
return output.New().Print(resp.Payload)
}

func (c *config) volumeClusterInfo() error {
params := volume.NewClusterInfoParams().WithPartitionid(helper.ViperString("partition"))
resp, err := c.cloud.Volume.ClusterInfo(params, nil)
Expand Down Expand Up @@ -328,3 +391,11 @@ delete snapshot: %q, all data will be lost forever.

return output.New().Print(resp.Payload)
}

func (c *config) listQoSPolicies() error {
resp, err := c.cloud.Volume.ListPolicies(volume.NewListPoliciesParams(), nil)
if err != nil {
return err
}
return output.New().Print(resp.Payload)
}
20 changes: 10 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/dustin/go-humanize v1.0.1
github.com/fatih/color v1.16.0
github.com/fi-ts/accounting-go v0.9.1
github.com/fi-ts/cloud-go v0.25.0
github.com/fi-ts/cloud-go v0.26.5
github.com/gardener/gardener v1.80.0
github.com/gardener/machine-controller-manager v0.50.1
github.com/go-openapi/runtime v0.28.0
Expand All @@ -19,7 +19,7 @@ require (
github.com/gosimple/slug v1.14.0
github.com/jinzhu/now v1.1.5
github.com/metal-stack/duros-go v0.4.7
github.com/metal-stack/metal-go v0.28.4
github.com/metal-stack/metal-go v0.29.0
github.com/metal-stack/metal-lib v0.16.2
github.com/metal-stack/updater v1.2.1
github.com/metal-stack/v v1.0.3
Expand Down Expand Up @@ -174,16 +174,16 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/oauth2 v0.19.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.20.0 // indirect
golang.org/x/tools v0.21.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
Expand Down
Loading
Loading