From bb0976280391680e2ad64bb8a635b707a44d6ba5 Mon Sep 17 00:00:00 2001 From: Chandler Ortman Date: Wed, 11 Feb 2026 13:44:15 -0800 Subject: [PATCH 1/3] Update capacity get command to use new API --- app/namespace.go | 91 ++++++++++++++++++++++++++++++++++++++++++- app/namespace_test.go | 21 +++++++--- 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/app/namespace.go b/app/namespace.go index 4784d17c..ca108644 100644 --- a/app/namespace.go +++ b/app/namespace.go @@ -386,6 +386,91 @@ func (c *NamespaceClient) getNamespaceCloudApi(namespace string) (*cloudNamespac return res.Namespace, nil } +func (c *NamespaceClient) getNamespaceCapacityInfoCloudApi(namespace string) (*cloudNamespace.NamespaceCapacityInfo, error) { + res, err := c.cloudAPIClient.GetNamespaceCapacityInfo(c.ctx, &cloudservice.GetNamespaceCapacityInfoRequest{ + Namespace: namespace, + }) + if err != nil { + return nil, err + } + if res.GetCapacityInfo() == nil || res.GetCapacityInfo().Namespace == "" { + // this should never happen, the server should return an error when the namespace capacity info is not found or invalid + return nil, fmt.Errorf("invalid namespace capacity info returned by server") + } + return res.CapacityInfo, nil +} + +// NamespaceCapacityInfoOutput is a flattened version of NamespaceCapacityInfo +// that maintains backwards compatibility by keeping provisioned/onDemand and +// latestRequest at the top level while adding new fields. +type NamespaceCapacityInfoOutput struct { + Namespace string `json:"namespace,omitempty"` + HasLegacyLimits bool `json:"hasLegacyLimits"` + // CurrentMode fields - flattened from CurrentCapacity + Provisioned *cloudNamespace.Capacity_Provisioned `json:"provisioned,omitempty"` + OnDemand *cloudNamespace.Capacity_OnDemand `json:"onDemand,omitempty"` + // LatestRequest - flattened from CurrentCapacity + LatestRequest *cloudNamespace.Capacity_Request `json:"latestRequest,omitempty"` + // New fields + ModeOptions *cloudNamespace.NamespaceCapacityInfo_CapacityModeOptions `json:"modeOptions,omitempty"` + Stats *NamespaceCapacityInfoOutput_Stats `json:"stats,omitempty"` +} + +// NamespaceCapacityInfoOutput_Stats wraps the proto Stats type to ensure +// numeric fields are always included in JSON output (no omitempty). +type NamespaceCapacityInfoOutput_Stats struct { + Aps *NamespaceCapacityInfoOutput_Stats_Summary `json:"aps,omitempty"` +} + +// NamespaceCapacityInfoOutput_Stats_Summary wraps the proto Stats_Summary type +// to ensure numeric fields are always included in JSON output (no omitempty). +type NamespaceCapacityInfoOutput_Stats_Summary struct { + Mean float64 `json:"mean"` + P90 float64 `json:"p90"` + P99 float64 `json:"p99"` +} + +// transformCapacityInfoForOutput flattens the NamespaceCapacityInfo structure +// to maintain backwards compatibility while including new fields. +func transformCapacityInfoForOutput(info *cloudNamespace.NamespaceCapacityInfo) *NamespaceCapacityInfoOutput { + if info == nil { + return nil + } + + output := &NamespaceCapacityInfoOutput{ + Namespace: info.Namespace, + HasLegacyLimits: info.HasLegacyLimits, + ModeOptions: info.ModeOptions, + } + + // Convert Stats to custom type to ensure zero values are included + if info.Stats != nil { + output.Stats = &NamespaceCapacityInfoOutput_Stats{} + if info.Stats.Aps != nil { + output.Stats.Aps = &NamespaceCapacityInfoOutput_Stats_Summary{ + Mean: info.Stats.Aps.Mean, + P90: info.Stats.Aps.P90, + P99: info.Stats.Aps.P99, + } + } + } + + // Flatten currentCapacity fields to top level + if info.CurrentCapacity != nil { + // Extract the current mode (provisioned or onDemand) + if prov := info.CurrentCapacity.GetProvisioned(); prov != nil { + output.Provisioned = prov + } + if od := info.CurrentCapacity.GetOnDemand(); od != nil { + output.OnDemand = od + } + // Extract latestRequest + output.LatestRequest = info.CurrentCapacity.LatestRequest + } + + return output +} + // TODO: deprecate this and use getNamespaceCloudApi everywhere func (c *NamespaceClient) getNamespace(namespace string) (*namespace.Namespace, error) { res, err := c.client.GetNamespace(c.ctx, &namespaceservice.GetNamespaceRequest{ @@ -1923,11 +2008,13 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut, NamespaceFlag, }, Action: func(ctx *cli.Context) error { - n, err := c.getNamespaceCloudApi(ctx.String(NamespaceFlagName)) + n, err := c.getNamespaceCapacityInfoCloudApi(ctx.String(NamespaceFlagName)) if err != nil { return err } - return PrintProto(n.GetCapacity()) + // Transform to flattened output structure for backwards compatibility + output := transformCapacityInfoForOutput(n) + return PrintObj(output) }, }, { diff --git a/app/namespace_test.go b/app/namespace_test.go index fe4ab8ed..4648e236 100644 --- a/app/namespace_test.go +++ b/app/namespace_test.go @@ -3306,17 +3306,26 @@ func (s *NamespaceTestSuite) TestGetNamespaceCapacity() { args: []string{"namespace", "capacity", "get", "--namespace", "ns1"}, mock: func() { s.mockCloudApiClient.EXPECT(). - GetNamespace(gomock.Any(), &cloudservice.GetNamespaceRequest{ + GetNamespaceCapacityInfo(gomock.Any(), &cloudservice.GetNamespaceCapacityInfoRequest{ Namespace: "ns1", - }).Return(&cloudservice.GetNamespaceResponse{ - Namespace: &cloudNamespace.Namespace{ - Namespace: "ns1", - Capacity: &cloudNamespace.Capacity{ + }).Return(&cloudservice.GetNamespaceCapacityInfoResponse{ + CapacityInfo: &cloudNamespace.NamespaceCapacityInfo{ + Namespace: "ns1", + HasLegacyLimits: false, + CurrentCapacity: &cloudNamespace.Capacity{ CurrentMode: &cloudNamespace.Capacity_Provisioned_{ Provisioned: &cloudNamespace.Capacity_Provisioned{ CurrentValue: 16.0, }, }, + LatestRequest: &cloudNamespace.Capacity_Request{ + State: cloudNamespace.STATE_CAPACITY_REQUEST_COMPLETED, + }, + }, + ModeOptions: &cloudNamespace.NamespaceCapacityInfo_CapacityModeOptions{ + Provisioned: &cloudNamespace.NamespaceCapacityInfo_CapacityModeOptions_Provisioned{ + ValidTruValues: []float64{2, 4, 8, 16}, + }, }, }, }, nil).Times(1) @@ -3328,7 +3337,7 @@ func (s *NamespaceTestSuite) TestGetNamespaceCapacity() { expectErr: true, mock: func() { s.mockCloudApiClient.EXPECT(). - GetNamespace(gomock.Any(), &cloudservice.GetNamespaceRequest{ + GetNamespaceCapacityInfo(gomock.Any(), &cloudservice.GetNamespaceCapacityInfoRequest{ Namespace: "ns1", }).Return(nil, errors.New("some error")).Times(1) }, From 6deefbdca9bebc8ad41ff726e85d35a2c837d09e Mon Sep 17 00:00:00 2001 From: Chandler Ortman Date: Wed, 11 Feb 2026 13:45:18 -0800 Subject: [PATCH 2/3] Update command usage message --- app/namespace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/namespace.go b/app/namespace.go index ca108644..13060474 100644 --- a/app/namespace.go +++ b/app/namespace.go @@ -2002,7 +2002,7 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut, Subcommands: []*cli.Command{ { Name: "get", - Usage: "Get namespace capacity settings", + Usage: "Get namespace capacity information", Aliases: []string{"g"}, Flags: []cli.Flag{ NamespaceFlag, From 7324bdad00b27c6e66ae9602a1409bcf3f6ada94 Mon Sep 17 00:00:00 2001 From: Chandler Ortman Date: Fri, 13 Feb 2026 17:10:20 -0800 Subject: [PATCH 3/3] Remove custom parsing, add test case --- app/namespace.go | 79 ++----------------------------------------- app/namespace_test.go | 26 ++++++++++---- 2 files changed, 22 insertions(+), 83 deletions(-) diff --git a/app/namespace.go b/app/namespace.go index 13060474..da72f9e4 100644 --- a/app/namespace.go +++ b/app/namespace.go @@ -400,77 +400,6 @@ func (c *NamespaceClient) getNamespaceCapacityInfoCloudApi(namespace string) (*c return res.CapacityInfo, nil } -// NamespaceCapacityInfoOutput is a flattened version of NamespaceCapacityInfo -// that maintains backwards compatibility by keeping provisioned/onDemand and -// latestRequest at the top level while adding new fields. -type NamespaceCapacityInfoOutput struct { - Namespace string `json:"namespace,omitempty"` - HasLegacyLimits bool `json:"hasLegacyLimits"` - // CurrentMode fields - flattened from CurrentCapacity - Provisioned *cloudNamespace.Capacity_Provisioned `json:"provisioned,omitempty"` - OnDemand *cloudNamespace.Capacity_OnDemand `json:"onDemand,omitempty"` - // LatestRequest - flattened from CurrentCapacity - LatestRequest *cloudNamespace.Capacity_Request `json:"latestRequest,omitempty"` - // New fields - ModeOptions *cloudNamespace.NamespaceCapacityInfo_CapacityModeOptions `json:"modeOptions,omitempty"` - Stats *NamespaceCapacityInfoOutput_Stats `json:"stats,omitempty"` -} - -// NamespaceCapacityInfoOutput_Stats wraps the proto Stats type to ensure -// numeric fields are always included in JSON output (no omitempty). -type NamespaceCapacityInfoOutput_Stats struct { - Aps *NamespaceCapacityInfoOutput_Stats_Summary `json:"aps,omitempty"` -} - -// NamespaceCapacityInfoOutput_Stats_Summary wraps the proto Stats_Summary type -// to ensure numeric fields are always included in JSON output (no omitempty). -type NamespaceCapacityInfoOutput_Stats_Summary struct { - Mean float64 `json:"mean"` - P90 float64 `json:"p90"` - P99 float64 `json:"p99"` -} - -// transformCapacityInfoForOutput flattens the NamespaceCapacityInfo structure -// to maintain backwards compatibility while including new fields. -func transformCapacityInfoForOutput(info *cloudNamespace.NamespaceCapacityInfo) *NamespaceCapacityInfoOutput { - if info == nil { - return nil - } - - output := &NamespaceCapacityInfoOutput{ - Namespace: info.Namespace, - HasLegacyLimits: info.HasLegacyLimits, - ModeOptions: info.ModeOptions, - } - - // Convert Stats to custom type to ensure zero values are included - if info.Stats != nil { - output.Stats = &NamespaceCapacityInfoOutput_Stats{} - if info.Stats.Aps != nil { - output.Stats.Aps = &NamespaceCapacityInfoOutput_Stats_Summary{ - Mean: info.Stats.Aps.Mean, - P90: info.Stats.Aps.P90, - P99: info.Stats.Aps.P99, - } - } - } - - // Flatten currentCapacity fields to top level - if info.CurrentCapacity != nil { - // Extract the current mode (provisioned or onDemand) - if prov := info.CurrentCapacity.GetProvisioned(); prov != nil { - output.Provisioned = prov - } - if od := info.CurrentCapacity.GetOnDemand(); od != nil { - output.OnDemand = od - } - // Extract latestRequest - output.LatestRequest = info.CurrentCapacity.LatestRequest - } - - return output -} - // TODO: deprecate this and use getNamespaceCloudApi everywhere func (c *NamespaceClient) getNamespace(namespace string) (*namespace.Namespace, error) { res, err := c.client.GetNamespace(c.ctx, &namespaceservice.GetNamespaceRequest{ @@ -1997,7 +1926,7 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut, }, { Name: "capacity", - Usage: "Manage namespace capacity settings", + Usage: "Manage namespace capacity", Aliases: []string{"cap"}, Subcommands: []*cli.Command{ { @@ -2008,13 +1937,11 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut, NamespaceFlag, }, Action: func(ctx *cli.Context) error { - n, err := c.getNamespaceCapacityInfoCloudApi(ctx.String(NamespaceFlagName)) + capacityInfo, err := c.getNamespaceCapacityInfoCloudApi(ctx.String(NamespaceFlagName)) if err != nil { return err } - // Transform to flattened output structure for backwards compatibility - output := transformCapacityInfoForOutput(n) - return PrintObj(output) + return PrintProto(capacityInfo) }, }, { diff --git a/app/namespace_test.go b/app/namespace_test.go index 4648e236..23eb2601 100644 --- a/app/namespace_test.go +++ b/app/namespace_test.go @@ -3302,7 +3302,7 @@ func (s *NamespaceTestSuite) TestGetNamespaceCapacity() { expectErr bool }{ { - name: "get namespace capacity - success", + name: "get namespace capacity - provisioned mode", args: []string{"namespace", "capacity", "get", "--namespace", "ns1"}, mock: func() { s.mockCloudApiClient.EXPECT(). @@ -3318,13 +3318,25 @@ func (s *NamespaceTestSuite) TestGetNamespaceCapacity() { CurrentValue: 16.0, }, }, - LatestRequest: &cloudNamespace.Capacity_Request{ - State: cloudNamespace.STATE_CAPACITY_REQUEST_COMPLETED, - }, }, - ModeOptions: &cloudNamespace.NamespaceCapacityInfo_CapacityModeOptions{ - Provisioned: &cloudNamespace.NamespaceCapacityInfo_CapacityModeOptions_Provisioned{ - ValidTruValues: []float64{2, 4, 8, 16}, + }, + }, nil).Times(1) + }, + }, + { + name: "get namespace capacity - on demand mode", + args: []string{"namespace", "capacity", "get", "--namespace", "ns2"}, + mock: func() { + s.mockCloudApiClient.EXPECT(). + GetNamespaceCapacityInfo(gomock.Any(), &cloudservice.GetNamespaceCapacityInfoRequest{ + Namespace: "ns2", + }).Return(&cloudservice.GetNamespaceCapacityInfoResponse{ + CapacityInfo: &cloudNamespace.NamespaceCapacityInfo{ + Namespace: "ns2", + HasLegacyLimits: false, + CurrentCapacity: &cloudNamespace.Capacity{ + CurrentMode: &cloudNamespace.Capacity_OnDemand_{ + OnDemand: &cloudNamespace.Capacity_OnDemand{}, }, }, },