diff --git a/app/namespace.go b/app/namespace.go index d48bdb8c..ea1eb49d 100644 --- a/app/namespace.go +++ b/app/namespace.go @@ -61,6 +61,11 @@ const ( AuthMethodAPIKeyOrMTLS = "api_key_or_mtls" ) +const ( + MaxPageSize = 1000 + DefaultPageSize = 100 +) + var ( AuthMethods = []string{ AuthMethodRestricted, @@ -121,7 +126,7 @@ var ( pageSizeFlag = &cli.IntFlag{ Name: "page-size", Usage: "The page size for list operations", - Value: 100, + Value: DefaultPageSize, } pageTokenFlag = &cli.StringFlag{ Name: "page-token", @@ -335,7 +340,20 @@ func (c *NamespaceClient) deleteRegion(ctx *cli.Context) error { return PrintProto(res.GetAsyncOperation()) } -func (c *NamespaceClient) listNamespaces() error { +func (c *NamespaceClient) listNamespaces(requestedPageToken string, pageSize int) error { + // Fetch a single page of namespaces. + if len(requestedPageToken) > 0 || pageSize > 0 { + res, err := c.client.ListNamespaces(c.ctx, &namespaceservice.ListNamespacesRequest{ + PageToken: requestedPageToken, + PageSize: int32(pageSize), + }) + if err != nil { + return err + } + return PrintProto(res) + } + + // Fetch all namespaces. totalRes := &namespaceservice.ListNamespacesResponse{} pageToken := "" for { @@ -1033,8 +1051,23 @@ func NewNamespaceCommand(getNamespaceClientFn GetNamespaceClientFn) (CommandOut, Name: "list", Usage: "List all known namespaces", Aliases: []string{"l"}, + Flags: []cli.Flag{ + pageTokenFlag, + &cli.IntFlag{ + Name: pageSizeFlagName, + Usage: "Number of namespaces to list per page", + }, + }, Action: func(ctx *cli.Context) error { - return c.listNamespaces() + if ctx.IsSet(pageSizeFlagName) { + if ctx.Int(pageSizeFlagName) <= 0 { + return fmt.Errorf("page size cannot be less than or equal to 0") + } + if ctx.Int(pageSizeFlagName) > MaxPageSize { + return fmt.Errorf("page size cannot be greater than %d", MaxPageSize) + } + } + return c.listNamespaces(ctx.String(pageTokenFlagName), ctx.Int(pageSizeFlagName)) }, }, { diff --git a/app/namespace_test.go b/app/namespace_test.go index 7fe9be00..fe4ab8ed 100644 --- a/app/namespace_test.go +++ b/app/namespace_test.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "os" + "strconv" "strings" "testing" @@ -105,6 +106,9 @@ func (s *NamespaceTestSuite) TestGet() { } func (s *NamespaceTestSuite) TestList() { + s.Error(s.RunCmd("namespace", "list", "--page-size", "0")) + s.Error(s.RunCmd("namespace", "list", "--page-size", "-1")) + s.Error(s.RunCmd("namespace", "list", "--page-size", strconv.Itoa(MaxPageSize+1))) s.mockService.EXPECT().ListNamespaces(gomock.Any(), &namespaceservice.ListNamespacesRequest{}).Return(nil, errors.New("some error")).Times(1) s.Error(s.RunCmd("namespace", "list")) @@ -144,8 +148,32 @@ func (s *NamespaceTestSuite) TestList() { s.mockService.EXPECT().ListNamespaces(gomock.Any(), &namespaceservice.ListNamespacesRequest{ PageToken: "token3", }).Return(&namespaceservice.ListNamespacesResponse{}, nil).Times(1) - s.NoError(s.RunCmd("namespace", "list")) + + s.mockService.EXPECT().ListNamespaces(gomock.Any(), &namespaceservice.ListNamespacesRequest{ + PageToken: "foo", + }).Return(&namespaceservice.ListNamespacesResponse{ + Namespaces: []string{"ns1", "ns2"}, + NextPageToken: "bar", + }, nil).Times(1) + s.NoError(s.RunCmd("namespace", "list", "--page-token", "foo")) + + s.mockService.EXPECT().ListNamespaces(gomock.Any(), &namespaceservice.ListNamespacesRequest{ + PageSize: 10, + }).Return(&namespaceservice.ListNamespacesResponse{ + Namespaces: []string{"ns1", "ns2"}, + NextPageToken: "foo", + }, nil).Times(1) + s.NoError(s.RunCmd("namespace", "list", "--page-size", "10")) + + s.mockService.EXPECT().ListNamespaces(gomock.Any(), &namespaceservice.ListNamespacesRequest{ + PageToken: "foo", + PageSize: 10, + }).Return(&namespaceservice.ListNamespacesResponse{ + Namespaces: []string{"ns1", "ns2"}, + NextPageToken: "bar", + }, nil).Times(1) + s.NoError(s.RunCmd("namespace", "list", "--page-token", "foo", "--page-size", "10")) } func (s *NamespaceTestSuite) TestDeleteProtection() {