diff --git a/cmd/completion/completion.go b/cmd/completion/completion.go index e798d1a..5d78903 100644 --- a/cmd/completion/completion.go +++ b/cmd/completion/completion.go @@ -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) @@ -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 diff --git a/cmd/output/order.go b/cmd/output/order.go index 38c75ca..65521fe 100644 --- a/cmd/output/order.go +++ b/cmd/output/order.go @@ -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 { @@ -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 { diff --git a/cmd/output/printer.go b/cmd/output/printer.go index 4504bde..3aae1ad 100644 --- a/cmd/output/printer.go +++ b/cmd/output/printer.go @@ -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: diff --git a/cmd/output/volume.go b/cmd/output/volume.go index 06db53c..0aebbb9 100644 --- a/cmd/output/volume.go +++ b/cmd/output/volume.go @@ -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" @@ -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) @@ -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 @@ -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) @@ -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() +} diff --git a/cmd/volume.go b/cmd/volume.go index 09369fb..718bb5c 100644 --- a/cmd/volume.go +++ b/cmd/volume.go @@ -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" @@ -44,6 +45,15 @@ func newVolumeCmd(c *config) *cobra.Command { }, ValidArgsFunction: c.comp.VolumeListCompletion, } + volumeSetQoSCmd := &cobra.Command{ + Use: "set-qos ", + 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 ", Short: "print a manifest for a volume", @@ -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") @@ -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]") @@ -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 } @@ -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) @@ -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) +} diff --git a/go.mod b/go.mod index fa948f0..8925780 100644 --- a/go.mod +++ b/go.mod @@ -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 @@ -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 @@ -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 diff --git a/go.sum b/go.sum index 967f2b6..383c36c 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fi-ts/accounting-go v0.9.1 h1:NFcsGg6l3tsK87khKgHQCtP242hiLsFYMPtKU+aX+Sg= github.com/fi-ts/accounting-go v0.9.1/go.mod h1:8ga8xix70wTxZNwdb0Ye4cEmL1miY6SeUio4vQLMBaI= -github.com/fi-ts/cloud-go v0.25.0 h1:+jDIMoEJ6i8BmRtUrbm3Rgs35Sqe3El5RKKsMzBayMA= -github.com/fi-ts/cloud-go v0.25.0/go.mod h1:FFod3G37QPbDDL7umk09EBAJocTSe68nY4gF6tOJSko= +github.com/fi-ts/cloud-go v0.26.5 h1:vqJ8Zxk/RDO8BeffaKgAX0ptueGKPGk7GhjgNq+bqXc= +github.com/fi-ts/cloud-go v0.26.5/go.mod h1:FFod3G37QPbDDL7umk09EBAJocTSe68nY4gF6tOJSko= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -295,8 +295,8 @@ github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/metal-stack/duros-go v0.4.7 h1:Rq948Q+b7sTqdScnJgxlvv12MRb9BPGsJXbaABEuzHY= github.com/metal-stack/duros-go v0.4.7/go.mod h1:rYi1/GvhVm3OQ3d+rB1PhIzq+6M8y4NgHR4ZkddKy7I= -github.com/metal-stack/metal-go v0.28.4 h1:cTI2jZqn59FNw0RkPAD7TYeK5YKJjj94YFJiuRl8eDo= -github.com/metal-stack/metal-go v0.28.4/go.mod h1:gYLZX3umsoZLWZ5d4MJdVbnR8eFXUTlLTK7tyx638As= +github.com/metal-stack/metal-go v0.29.0 h1:EuJ7u/L+3lsby+kzrE0aF6gBIBDKPENqvOO2idGhMqw= +github.com/metal-stack/metal-go v0.29.0/go.mod h1:gYLZX3umsoZLWZ5d4MJdVbnR8eFXUTlLTK7tyx638As= github.com/metal-stack/metal-lib v0.16.2 h1:RJls/Spai4h5xr3BEmQt9UdWNN4RB9+SOINoZcjYaA8= github.com/metal-stack/metal-lib v0.16.2/go.mod h1:nyNGI4DZFOcWbSoq2Y6V3SHpFxuXBIqYBZHTb6cy//s= github.com/metal-stack/security v0.8.0 h1:tVaSDB9m5clwYrnLyaXfPy7mQlJTnmeoHscG+RUy/xo= @@ -439,11 +439,11 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/W golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp/typeparams v0.0.0-20230905200255-921286631fa9 h1:j3D9DvWRpUfIyFfDPws7LoIZ2MAI1OJHdQXtTnYtN+k= golang.org/x/exp/typeparams v0.0.0-20230905200255-921286631fa9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= @@ -465,12 +465,12 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= -golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -493,14 +493,14 @@ golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -511,8 +511,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=