cli: add pagination flags to service info command. (#12730)

This commit is contained in:
James Rasell 2022-04-22 10:32:40 +02:00 committed by GitHub
parent d200a66509
commit 046831466c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 128 additions and 9 deletions

View File

@ -99,7 +99,7 @@ func (s *HTTPServer) serviceGetRequest(
if err := s.agent.RPC(structs.ServiceRegistrationGetServiceRPCMethod, &args, &reply); err != nil {
return nil, err
}
setIndex(resp, reply.Index)
setMeta(resp, &reply.QueryMeta)
if reply.Services == nil {
reply.Services = make([]*structs.ServiceRegistration, 0)

View File

@ -2,6 +2,7 @@ package command
import (
"fmt"
"os"
"sort"
"strings"
@ -37,6 +38,12 @@ Service Info Options:
-verbose
Display full information.
-per-page
How many results to show per page.
-page-token
Where to start pagination.
-filter
Specifies an expression used to filter query results.
@ -57,10 +64,12 @@ func (s *ServiceInfoCommand) Synopsis() string {
func (s *ServiceInfoCommand) AutocompleteFlags() complete.Flags {
return mergeAutocompleteFlags(s.Meta.AutocompleteFlags(FlagSetClient),
complete.Flags{
"-json": complete.PredictNothing,
"-filter": complete.PredictAnything,
"-t": complete.PredictAnything,
"-verbose": complete.PredictNothing,
"-json": complete.PredictNothing,
"-filter": complete.PredictAnything,
"-per-page": complete.PredictAnything,
"-page-token": complete.PredictAnything,
"-t": complete.PredictAnything,
"-verbose": complete.PredictNothing,
})
}
@ -70,8 +79,9 @@ func (s *ServiceInfoCommand) Name() string { return "service info" }
// Run satisfies the cli.Command Run function.
func (s *ServiceInfoCommand) Run(args []string) int {
var (
json, verbose bool
tmpl, filter string
json, verbose bool
perPage int
tmpl, filter, pageToken string
)
flags := s.Meta.FlagSet(s.Name(), FlagSetClient)
@ -80,6 +90,8 @@ func (s *ServiceInfoCommand) Run(args []string) int {
flags.BoolVar(&verbose, "verbose", false, "")
flags.StringVar(&tmpl, "t", "", "")
flags.StringVar(&filter, "filter", "", "")
flags.IntVar(&perPage, "per-page", 0, "")
flags.StringVar(&pageToken, "page-token", "", "")
if err := flags.Parse(args); err != nil {
return 1
}
@ -99,10 +111,12 @@ func (s *ServiceInfoCommand) Run(args []string) int {
// Set up the options to capture any filter passed.
opts := api.QueryOptions{
Filter: filter,
Filter: filter,
PerPage: int32(perPage),
NextToken: pageToken,
}
serviceInfo, _, err := client.Services().Get(args[0], &opts)
serviceInfo, qm, err := client.Services().Get(args[0], &opts)
if err != nil {
s.Ui.Error(fmt.Sprintf("Error listing service registrations: %s", err))
return 1
@ -147,6 +161,12 @@ func (s *ServiceInfoCommand) Run(args []string) int {
} else {
s.formatOutput(sortedJobID, jobIDServices)
}
if qm.NextToken != "" {
s.Ui.Output(fmt.Sprintf("\nResults have been paginated. To get the next page run: \n\n%s ",
argsWithNewPageToken(os.Args, qm.NextToken)))
}
return 0
}
@ -194,3 +214,41 @@ func (s *ServiceInfoCommand) formatVerboseOutput(jobIDs []string, jobServices ma
}
}
}
// argsWithNewPageToken takes the arguments which called the CLI and modifies
// them to include the correct next token. The function ensures the argument
// ordering is maintained which is vital when using pagination on info related
// calls which have an identifier as their final argument.
func argsWithNewPageToken(osArgs []string, nextToken string) string {
// Copy the arguments into a new array which will be modified and make a
// note of the original length as we may need to modify the length if this
// is the first pagination call without a next token.
newArgs := osArgs
numArgs := len(newArgs)
for i := 0; i < numArgs; i++ {
// If the caller already included a pagination token, replace this
// occurrence with the new next token and exit as we don't need to
// modify any other arguments.
if strings.HasPrefix(newArgs[i], "-page-token") {
if strings.Contains(newArgs[i], "=") {
newArgs[i] = "-page-token=" + nextToken
} else {
newArgs[i+1] = nextToken
}
break
}
// If we have reached the final argument (service name) and are still
// looping we have not added the next token argument. Add this while
// ensuring the service name if the final argument on the command.
if i == numArgs-1 {
serviceName := newArgs[i]
newArgs[i] = "-page-token=" + nextToken
newArgs = append(newArgs, serviceName)
}
}
return strings.Join(newArgs, " ")
}

View File

@ -120,3 +120,58 @@ func TestServiceInfoCommand_Run(t *testing.T) {
ui.OutputWriter.Reset()
ui.ErrorWriter.Reset()
}
func Test_argsWithNewPageToken(t *testing.T) {
ci.Parallel(t)
testCases := []struct {
inputOsArgs []string
inputNextToken string
expectedOutput string
name string
}{
{
inputOsArgs: []string{"nomad", "service", "info", "-page-token=abcdef", "example-cache"},
inputNextToken: "ghijkl",
expectedOutput: "nomad service info -page-token=ghijkl example-cache",
name: "page token with equals sign",
},
{
inputOsArgs: []string{"nomad", "service", "info", "-page-token", "abcdef", "example-cache"},
inputNextToken: "ghijkl",
expectedOutput: "nomad service info -page-token ghijkl example-cache",
name: "page token with whitespace gap",
},
{
inputOsArgs: []string{"nomad", "service", "info", "-per-page", "3", "-page-token", "abcdef", "example-cache"},
inputNextToken: "ghijkl",
expectedOutput: "nomad service info -per-page 3 -page-token ghijkl example-cache",
name: "per page and page token",
},
{
inputOsArgs: []string{"nomad", "service", "info", "-page-token", "abcdef", "-per-page", "3", "example-cache"},
inputNextToken: "ghijkl",
expectedOutput: "nomad service info -page-token ghijkl -per-page 3 example-cache",
name: "page token and per page",
},
{
inputOsArgs: []string{"nomad", "service", "info", "-page-token", "abcdef", "-per-page=3", "example-cache"},
inputNextToken: "ghijkl",
expectedOutput: "nomad service info -page-token ghijkl -per-page=3 example-cache",
name: "page token and per page with equal",
},
{
inputOsArgs: []string{"nomad", "service", "info", "-verbose", "-page-token", "abcdef", "-per-page=3", "example-cache"},
inputNextToken: "ghijkl",
expectedOutput: "nomad service info -verbose -page-token ghijkl -per-page=3 example-cache",
name: "page token per page with verbose",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actualOutput := argsWithNewPageToken(tc.inputOsArgs, tc.inputNextToken)
require.Equal(t, tc.expectedOutput, actualOutput)
})
}
}

View File

@ -30,6 +30,12 @@ capability for the service's namespace.
## Info Options
- `-per-page`: How many results to show per page.
- `-page-token`: Where to start pagination.
- `-filter`: Specifies an expression used to filter query results.
- `-json` : Output the service registrations in JSON format.
- `-t` : Format and display the service registrations using a Go template.