aboutsummaryrefslogtreecommitdiffstats
path: root/client/go
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-07-12 15:42:56 +0200
committerMartin Polden <mpolden@mpolden.no>2023-07-12 18:28:29 +0200
commit947b0299ac998a9a833b69a0b0a2a0de8098b67c (patch)
tree78ef70ed2215fa93f57ad6f7fb5bbf8dd593b004 /client/go
parent97f0cf32edba5e6545dc027cdcdaaec125bad37d (diff)
Wait by default in deploy commands
Diffstat (limited to 'client/go')
-rw-r--r--client/go/internal/cli/cmd/config.go18
-rw-r--r--client/go/internal/cli/cmd/config_test.go8
-rw-r--r--client/go/internal/cli/cmd/curl.go5
-rw-r--r--client/go/internal/cli/cmd/deploy.go44
-rw-r--r--client/go/internal/cli/cmd/deploy_test.go33
-rw-r--r--client/go/internal/cli/cmd/document.go46
-rw-r--r--client/go/internal/cli/cmd/feed.go12
-rw-r--r--client/go/internal/cli/cmd/prod.go7
-rw-r--r--client/go/internal/cli/cmd/query.go8
-rw-r--r--client/go/internal/cli/cmd/root.go29
-rw-r--r--client/go/internal/cli/cmd/status.go40
-rw-r--r--client/go/internal/cli/cmd/test.go18
-rw-r--r--client/go/internal/cli/cmd/visit.go4
-rw-r--r--client/go/internal/cli/cmd/visit_test.go2
14 files changed, 132 insertions, 142 deletions
diff --git a/client/go/internal/cli/cmd/config.go b/client/go/internal/cli/cmd/config.go
index 409254c4349..eb79a2004c4 100644
--- a/client/go/internal/cli/cmd/config.go
+++ b/client/go/internal/cli/cmd/config.go
@@ -337,18 +337,6 @@ func (c *Config) targetOrURL() (string, error) {
return targetType, nil
}
-func (c *Config) timeout() (time.Duration, error) {
- wait, ok := c.get(waitFlag)
- if !ok {
- return 0, nil
- }
- secs, err := strconv.Atoi(wait)
- if err != nil {
- return 0, err
- }
- return time.Duration(secs) * time.Second, nil
-}
-
func (c *Config) isQuiet() bool {
quiet, _ := c.get(quietFlag)
return quiet == "true"
@@ -629,12 +617,6 @@ func (c *Config) set(option, value string) error {
case clusterFlag:
c.config.Set(clusterFlag, value)
return nil
- case waitFlag:
- if n, err := strconv.Atoi(value); err != nil || n < 0 {
- return fmt.Errorf("%s option must be an integer >= 0, got %q", option, value)
- }
- c.config.Set(option, value)
- return nil
case colorFlag:
switch value {
case "auto", "never", "always":
diff --git a/client/go/internal/cli/cmd/config_test.go b/client/go/internal/cli/cmd/config_test.go
index 3a81b93ea0d..14a3cf7cbbc 100644
--- a/client/go/internal/cli/cmd/config_test.go
+++ b/client/go/internal/cli/cmd/config_test.go
@@ -54,12 +54,6 @@ func TestConfig(t *testing.T) {
assertConfigCommand(t, configHome, "", "config", "set", "instance", "i2")
assertConfigCommand(t, configHome, "instance = i2\n", "config", "get", "instance")
- // wait
- assertConfigCommandErr(t, configHome, "Error: wait option must be an integer >= 0, got \"foo\"\n", "config", "set", "wait", "foo")
- assertConfigCommand(t, configHome, "", "config", "set", "wait", "60")
- assertConfigCommand(t, configHome, "wait = 60\n", "config", "get", "wait")
- assertConfigCommand(t, configHome, "wait = 30\n", "config", "get", "--wait", "30", "wait") // flag overrides global config
-
// color
assertConfigCommandErr(t, configHome, "Error: invalid option or value: color = foo\n", "config", "set", "color", "foo")
assertConfigCommand(t, configHome, "", "config", "set", "color", "never")
@@ -74,6 +68,7 @@ func TestConfig(t *testing.T) {
// zone
assertConfigCommand(t, configHome, "", "config", "set", "zone", "dev.us-east-1")
assertConfigCommand(t, configHome, "zone = dev.us-east-1\n", "config", "get", "zone")
+ assertConfigCommand(t, configHome, "zone = prod.us-north-1\n", "config", "get", "--zone", "prod.us-north-1", "zone") // flag overrides global config
// Write empty value to YAML config, which should be ignored. This is for compatibility with older config formats
configFile := filepath.Join(configHome, "config.yaml")
@@ -118,7 +113,6 @@ color = auto
instance = foo
quiet = false
target = cloud
-wait = 0
zone = <unset>
`, "config", "get")
diff --git a/client/go/internal/cli/cmd/curl.go b/client/go/internal/cli/cmd/curl.go
index 3d5aaff24dc..3009cab2b5e 100644
--- a/client/go/internal/cli/cmd/curl.go
+++ b/client/go/internal/cli/cmd/curl.go
@@ -6,6 +6,7 @@ import (
"log"
"os"
"strings"
+ "time"
"github.com/spf13/cobra"
"github.com/vespa-engine/vespa/client/go/internal/curl"
@@ -14,6 +15,7 @@ import (
func newCurlCmd(cli *CLI) *cobra.Command {
var (
+ waitSecs int
dryRun bool
curlService string
)
@@ -37,7 +39,7 @@ $ vespa curl -- -v --data-urlencode "yql=select * from music where album contain
if err != nil {
return err
}
- service, err := target.Service(curlService, 0, 0, cli.config.cluster())
+ service, err := target.Service(curlService, time.Duration(waitSecs)*time.Second, 0, cli.config.cluster())
if err != nil {
return err
}
@@ -72,6 +74,7 @@ $ vespa curl -- -v --data-urlencode "yql=select * from music where album contain
}
cmd.Flags().BoolVarP(&dryRun, "dry-run", "n", false, "Print the curl command that would be executed")
cmd.Flags().StringVarP(&curlService, "service", "s", "query", "Which service to query. Must be \"deploy\", \"document\" or \"query\"")
+ cli.bindWaitFlag(cmd, 60, &waitSecs)
return cmd
}
diff --git a/client/go/internal/cli/cmd/deploy.go b/client/go/internal/cli/cmd/deploy.go
index 35b9ee0f300..ef32d7f01b7 100644
--- a/client/go/internal/cli/cmd/deploy.go
+++ b/client/go/internal/cli/cmd/deploy.go
@@ -9,6 +9,7 @@ import (
"io"
"log"
"strconv"
+ "time"
"github.com/fatih/color"
"github.com/spf13/cobra"
@@ -18,6 +19,7 @@ import (
func newDeployCmd(cli *CLI) *cobra.Command {
var (
+ waitSecs int
logLevelArg string
versionArg string
copyCert bool
@@ -57,10 +59,8 @@ $ vespa deploy -t cloud -z perf.aws-us-east-1c`,
if err != nil {
return err
}
- opts, err := cli.createDeploymentOptions(pkg, target)
- if err != nil {
- return err
- }
+ timeout := time.Duration(waitSecs) * time.Second
+ opts := vespa.DeploymentOptions{ApplicationPackage: pkg, Target: target, Timeout: timeout}
if versionArg != "" {
version, err := version.Parse(versionArg)
if err != nil {
@@ -95,12 +95,13 @@ $ vespa deploy -t cloud -z perf.aws-us-east-1c`,
opts.Target.Deployment().Application.Instance, opts.Target.Deployment().Zone.Environment, opts.Target.Deployment().Zone.Region,
result.ID)))
}
- return waitForQueryService(cli, target, result.ID)
+ return waitForQueryService(cli, target, result.ID, timeout)
},
}
cmd.Flags().StringVarP(&logLevelArg, "log-level", "l", "error", `Log level for Vespa logs. Must be "error", "warning", "info" or "debug"`)
cmd.Flags().StringVarP(&versionArg, "version", "V", "", `Override the Vespa runtime version to use in Vespa Cloud`)
cmd.Flags().BoolVarP(&copyCert, "add-cert", "A", false, `Copy certificate of the configured application to the current application package`)
+ cli.bindWaitFlag(cmd, 60, &waitSecs)
return cmd
}
@@ -120,10 +121,7 @@ func newPrepareCmd(cli *CLI) *cobra.Command {
if err != nil {
return err
}
- opts, err := cli.createDeploymentOptions(pkg, target)
- if err != nil {
- return err
- }
+ opts := vespa.DeploymentOptions{ApplicationPackage: pkg, Target: target}
var result vespa.PrepareResult
err = cli.spinner(cli.Stderr, "Uploading application package ...", func() error {
result, err = vespa.Prepare(opts)
@@ -143,7 +141,8 @@ func newPrepareCmd(cli *CLI) *cobra.Command {
}
func newActivateCmd(cli *CLI) *cobra.Command {
- return &cobra.Command{
+ var waitSecs int
+ cmd := &cobra.Command{
Use: "activate",
Short: "Activate (deploy) a previously prepared application package",
Args: cobra.MaximumNArgs(1),
@@ -162,31 +161,26 @@ func newActivateCmd(cli *CLI) *cobra.Command {
if err != nil {
return err
}
- opts, err := cli.createDeploymentOptions(pkg, target)
- if err != nil {
- return err
- }
+ timeout := time.Duration(waitSecs) * time.Second
+ opts := vespa.DeploymentOptions{ApplicationPackage: pkg, Target: target, Timeout: timeout}
err = vespa.Activate(sessionID, opts)
if err != nil {
return err
}
cli.printSuccess("Activated ", color.CyanString(pkg.Path), " with session ", sessionID)
- return waitForQueryService(cli, target, sessionID)
+ return waitForQueryService(cli, target, sessionID, timeout)
},
}
+ cli.bindWaitFlag(cmd, 60, &waitSecs)
+ return cmd
}
-func waitForQueryService(cli *CLI, target vespa.Target, sessionOrRunID int64) error {
- timeout, err := cli.config.timeout()
- if err != nil {
- return err
- }
- if timeout > 0 {
- log.Println()
- _, err := cli.service(target, vespa.QueryService, sessionOrRunID, cli.config.cluster())
- return err
+func waitForQueryService(cli *CLI, target vespa.Target, sessionOrRunID int64, timeout time.Duration) error {
+ if timeout == 0 {
+ return nil
}
- return nil
+ _, err := cli.service(target, vespa.QueryService, sessionOrRunID, cli.config.cluster(), timeout)
+ return err
}
func printPrepareLog(stderr io.Writer, result vespa.PrepareResult) {
diff --git a/client/go/internal/cli/cmd/deploy_test.go b/client/go/internal/cli/cmd/deploy_test.go
index 9e82723e816..16aa3fd0ed8 100644
--- a/client/go/internal/cli/cmd/deploy_test.go
+++ b/client/go/internal/cli/cmd/deploy_test.go
@@ -40,7 +40,7 @@ Hint: Pass --add-cert to use the certificate of the current application
`
assert.Equal(t, certError, stderr.String())
- require.Nil(t, cli.Run("deploy", "--add-cert", pkgDir))
+ require.Nil(t, cli.Run("deploy", "--add-cert", "--wait=0", pkgDir))
assert.Contains(t, stdout.String(), "Success: Triggered deployment")
// Answer interactive certificate copy prompt
@@ -53,11 +53,11 @@ Hint: Pass --add-cert to use the certificate of the current application
var buf bytes.Buffer
buf.WriteString("wat\nthe\nfck\nn\n")
cli.Stdin = &buf
- require.NotNil(t, cli.Run("deploy", "--add-cert=false", pkgDir2))
+ require.NotNil(t, cli.Run("deploy", "--add-cert=false", "--wait=0", pkgDir2))
warning := "Warning: Application package does not contain security/clients.pem, which is required for deployments to Vespa Cloud\n"
assert.Equal(t, warning+strings.Repeat("Error: please answer 'y' or 'n'\n", 3)+certError, stderr.String())
buf.WriteString("y\n")
- require.Nil(t, cli.Run("deploy", "--add-cert=false", pkgDir2))
+ require.Nil(t, cli.Run("deploy", "--add-cert=false", "--wait=0", pkgDir2))
assert.Contains(t, stdout.String(), "Success: Triggered deployment")
}
@@ -68,17 +68,17 @@ func TestPrepareZip(t *testing.T) {
func TestActivateZip(t *testing.T) {
assertActivate("testdata/applications/withTarget/target/application.zip",
- []string{"activate", "testdata/applications/withTarget/target/application.zip"}, t)
+ []string{"activate", "--wait=0", "testdata/applications/withTarget/target/application.zip"}, t)
}
func TestDeployZip(t *testing.T) {
assertDeploy("testdata/applications/withTarget/target/application.zip",
- []string{"deploy", "testdata/applications/withTarget/target/application.zip"}, t)
+ []string{"deploy", "--wait=0", "testdata/applications/withTarget/target/application.zip"}, t)
}
func TestDeployZipWithURLTargetArgument(t *testing.T) {
applicationPackage := "testdata/applications/withTarget/target/application.zip"
- arguments := []string{"deploy", "testdata/applications/withTarget/target/application.zip", "-t", "http://target:19071"}
+ arguments := []string{"deploy", "--wait=0", "testdata/applications/withTarget/target/application.zip", "-t", "http://target:19071"}
client := &mock.HTTPClient{}
cli, stdout, _ := newTestCLI(t)
@@ -92,27 +92,27 @@ func TestDeployZipWithURLTargetArgument(t *testing.T) {
func TestDeployZipWithLocalTargetArgument(t *testing.T) {
assertDeploy("testdata/applications/withTarget/target/application.zip",
- []string{"deploy", "testdata/applications/withTarget/target/application.zip", "-t", "local"}, t)
+ []string{"deploy", "--wait=0", "testdata/applications/withTarget/target/application.zip", "-t", "local"}, t)
}
func TestDeploySourceDirectory(t *testing.T) {
assertDeploy("testdata/applications/withSource/src/main/application",
- []string{"deploy", "testdata/applications/withSource/src/main/application"}, t)
+ []string{"deploy", "--wait=0", "testdata/applications/withSource/src/main/application"}, t)
}
func TestDeployApplicationDirectoryWithSource(t *testing.T) {
assertDeploy("testdata/applications/withSource/src/main/application",
- []string{"deploy", "testdata/applications/withSource"}, t)
+ []string{"deploy", "--wait=0", "testdata/applications/withSource"}, t)
}
func TestDeployApplicationDirectoryWithPomAndTarget(t *testing.T) {
assertDeploy("testdata/applications/withTarget/target/application.zip",
- []string{"deploy", "testdata/applications/withTarget"}, t)
+ []string{"deploy", "--wait=0", "testdata/applications/withTarget"}, t)
}
func TestDeployApplicationDirectoryWithPomAndEmptyTarget(t *testing.T) {
cli, _, stderr := newTestCLI(t)
- assert.NotNil(t, cli.Run("deploy", "testdata/applications/withEmptyTarget"))
+ assert.NotNil(t, cli.Run("deploy", "--wait=0", "testdata/applications/withEmptyTarget"))
assert.Equal(t,
"Error: found pom.xml, but target/application.zip does not exist: run 'mvn package' first\n",
stderr.String())
@@ -228,7 +228,14 @@ func assertApplicationPackageError(t *testing.T, cmd string, status int, expecte
client.NextResponseString(status, returnBody)
cli, _, stderr := newTestCLI(t)
cli.httpClient = client
- assert.NotNil(t, cli.Run(cmd, "testdata/applications/withTarget/target/application.zip"))
+ args := []string{}
+ args = append(args, cmd)
+ switch cmd {
+ case "activate", "deploy":
+ args = append(args, "--wait=0")
+ }
+ args = append(args, "testdata/applications/withTarget/target/application.zip")
+ assert.NotNil(t, cli.Run(args...))
assert.Equal(t,
"Error: invalid application package (Status "+strconv.Itoa(status)+")\n"+expectedMessage+"\n",
stderr.String())
@@ -240,7 +247,7 @@ func assertDeployServerError(t *testing.T, status int, errorMessage string) {
client.NextResponseString(status, errorMessage)
cli, _, stderr := newTestCLI(t)
cli.httpClient = client
- assert.NotNil(t, cli.Run("deploy", "testdata/applications/withTarget/target/application.zip"))
+ assert.NotNil(t, cli.Run("deploy", "--wait=0", "testdata/applications/withTarget/target/application.zip"))
assert.Equal(t,
"Error: error from deploy api at 127.0.0.1:19071 (Status "+strconv.Itoa(status)+"):\n"+errorMessage+"\n",
stderr.String())
diff --git a/client/go/internal/cli/cmd/document.go b/client/go/internal/cli/cmd/document.go
index 6a07121a13b..c31f8c34d14 100644
--- a/client/go/internal/cli/cmd/document.go
+++ b/client/go/internal/cli/cmd/document.go
@@ -23,9 +23,10 @@ import (
"github.com/vespa-engine/vespa/client/go/internal/vespa/document"
)
-func addDocumentFlags(cmd *cobra.Command, printCurl *bool, timeoutSecs *int) {
+func addDocumentFlags(cli *CLI, cmd *cobra.Command, printCurl *bool, timeoutSecs, waitSecs *int) {
cmd.PersistentFlags().BoolVarP(printCurl, "verbose", "v", false, "Print the equivalent curl command for the document operation")
cmd.PersistentFlags().IntVarP(timeoutSecs, "timeout", "T", 60, "Timeout for the document request in seconds")
+ cli.bindWaitFlag(cmd, 0, waitSecs)
}
type serviceWithCurl struct {
@@ -57,8 +58,8 @@ func (s *serviceWithCurl) Do(request *http.Request, timeout time.Duration) (*htt
return s.service.Do(request, timeout)
}
-func documentClient(cli *CLI, timeoutSecs int, printCurl bool) (*document.Client, *serviceWithCurl, error) {
- docService, err := documentService(cli)
+func documentClient(cli *CLI, timeoutSecs, waitSecs int, printCurl bool) (*document.Client, *serviceWithCurl, error) {
+ docService, err := documentService(cli, waitSecs)
if err != nil {
return nil, nil, err
}
@@ -78,8 +79,8 @@ func documentClient(cli *CLI, timeoutSecs int, printCurl bool) (*document.Client
return client, service, nil
}
-func sendOperation(op document.Operation, args []string, timeoutSecs int, printCurl bool, cli *CLI) error {
- client, service, err := documentClient(cli, timeoutSecs, printCurl)
+func sendOperation(op document.Operation, args []string, timeoutSecs, waitSecs int, printCurl bool, cli *CLI) error {
+ client, service, err := documentClient(cli, timeoutSecs, waitSecs, printCurl)
if err != nil {
return err
}
@@ -122,8 +123,8 @@ func sendOperation(op document.Operation, args []string, timeoutSecs int, printC
return printResult(cli, operationResult(false, doc, service.service, result), false)
}
-func readDocument(id string, timeoutSecs int, printCurl bool, cli *CLI) error {
- client, service, err := documentClient(cli, timeoutSecs, printCurl)
+func readDocument(id string, timeoutSecs, waitSecs int, printCurl bool, cli *CLI) error {
+ client, service, err := documentClient(cli, timeoutSecs, waitSecs, printCurl)
if err != nil {
return err
}
@@ -157,6 +158,7 @@ func newDocumentCmd(cli *CLI) *cobra.Command {
var (
printCurl bool
timeoutSecs int
+ waitSecs int
)
cmd := &cobra.Command{
Use: "document json-file",
@@ -176,10 +178,10 @@ should be used instead of this.`,
SilenceUsage: true,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
- return sendOperation(-1, args, timeoutSecs, printCurl, cli)
+ return sendOperation(-1, args, timeoutSecs, waitSecs, printCurl, cli)
},
}
- addDocumentFlags(cmd, &printCurl, &timeoutSecs)
+ addDocumentFlags(cli, cmd, &printCurl, &timeoutSecs, &waitSecs)
return cmd
}
@@ -187,6 +189,7 @@ func newDocumentPutCmd(cli *CLI) *cobra.Command {
var (
printCurl bool
timeoutSecs int
+ waitSecs int
)
cmd := &cobra.Command{
Use: "put [id] json-file",
@@ -200,10 +203,10 @@ $ vespa document put id:mynamespace:music::a-head-full-of-dreams src/test/resour
DisableAutoGenTag: true,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
- return sendOperation(document.OperationPut, args, timeoutSecs, printCurl, cli)
+ return sendOperation(document.OperationPut, args, timeoutSecs, waitSecs, printCurl, cli)
},
}
- addDocumentFlags(cmd, &printCurl, &timeoutSecs)
+ addDocumentFlags(cli, cmd, &printCurl, &timeoutSecs, &waitSecs)
return cmd
}
@@ -211,6 +214,7 @@ func newDocumentUpdateCmd(cli *CLI) *cobra.Command {
var (
printCurl bool
timeoutSecs int
+ waitSecs int
)
cmd := &cobra.Command{
Use: "update [id] json-file",
@@ -223,10 +227,10 @@ $ vespa document update id:mynamespace:music::a-head-full-of-dreams src/test/res
DisableAutoGenTag: true,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
- return sendOperation(document.OperationUpdate, args, timeoutSecs, printCurl, cli)
+ return sendOperation(document.OperationUpdate, args, timeoutSecs, waitSecs, printCurl, cli)
},
}
- addDocumentFlags(cmd, &printCurl, &timeoutSecs)
+ addDocumentFlags(cli, cmd, &printCurl, &timeoutSecs, &waitSecs)
return cmd
}
@@ -234,6 +238,7 @@ func newDocumentRemoveCmd(cli *CLI) *cobra.Command {
var (
printCurl bool
timeoutSecs int
+ waitSecs int
)
cmd := &cobra.Command{
Use: "remove id | json-file",
@@ -247,7 +252,7 @@ $ vespa document remove id:mynamespace:music::a-head-full-of-dreams`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if strings.HasPrefix(args[0], "id:") {
- client, service, err := documentClient(cli, timeoutSecs, printCurl)
+ client, service, err := documentClient(cli, timeoutSecs, waitSecs, printCurl)
if err != nil {
return err
}
@@ -259,11 +264,11 @@ $ vespa document remove id:mynamespace:music::a-head-full-of-dreams`,
result := client.Send(doc)
return printResult(cli, operationResult(false, doc, service.service, result), false)
} else {
- return sendOperation(document.OperationRemove, args, timeoutSecs, printCurl, cli)
+ return sendOperation(document.OperationRemove, args, timeoutSecs, waitSecs, printCurl, cli)
}
},
}
- addDocumentFlags(cmd, &printCurl, &timeoutSecs)
+ addDocumentFlags(cli, cmd, &printCurl, &timeoutSecs, &waitSecs)
return cmd
}
@@ -271,6 +276,7 @@ func newDocumentGetCmd(cli *CLI) *cobra.Command {
var (
printCurl bool
timeoutSecs int
+ waitSecs int
)
cmd := &cobra.Command{
Use: "get id",
@@ -280,19 +286,19 @@ func newDocumentGetCmd(cli *CLI) *cobra.Command {
SilenceUsage: true,
Example: `$ vespa document get id:mynamespace:music::a-head-full-of-dreams`,
RunE: func(cmd *cobra.Command, args []string) error {
- return readDocument(args[0], timeoutSecs, printCurl, cli)
+ return readDocument(args[0], timeoutSecs, waitSecs, printCurl, cli)
},
}
- addDocumentFlags(cmd, &printCurl, &timeoutSecs)
+ addDocumentFlags(cli, cmd, &printCurl, &timeoutSecs, &waitSecs)
return cmd
}
-func documentService(cli *CLI) (*vespa.Service, error) {
+func documentService(cli *CLI, waitSecs int) (*vespa.Service, error) {
target, err := cli.target(targetOptions{})
if err != nil {
return nil, err
}
- return cli.service(target, vespa.DocumentService, 0, cli.config.cluster())
+ return cli.service(target, vespa.DocumentService, 0, cli.config.cluster(), time.Duration(waitSecs)*time.Second)
}
func printResult(cli *CLI, result util.OperationResult, payloadOnlyOnSuccess bool) error {
diff --git a/client/go/internal/cli/cmd/feed.go b/client/go/internal/cli/cmd/feed.go
index fb01998b83f..7d4b9cc8042 100644
--- a/client/go/internal/cli/cmd/feed.go
+++ b/client/go/internal/cli/cmd/feed.go
@@ -16,7 +16,7 @@ import (
"github.com/vespa-engine/vespa/client/go/internal/vespa/document"
)
-func addFeedFlags(cmd *cobra.Command, options *feedOptions) {
+func addFeedFlags(cli *CLI, cmd *cobra.Command, options *feedOptions) {
cmd.PersistentFlags().IntVar(&options.connections, "connections", 8, "The number of connections to use")
cmd.PersistentFlags().StringVar(&options.compression, "compression", "auto", `Compression mode to use. Default is "auto" which compresses large documents. Must be "auto", "gzip" or "none"`)
cmd.PersistentFlags().IntVar(&options.timeoutSecs, "timeout", 0, "Individual feed operation timeout in seconds. 0 to disable (default 0)")
@@ -34,6 +34,7 @@ func addFeedFlags(cmd *cobra.Command, options *feedOptions) {
// Hide these flags as they are intended for internal use
cmd.PersistentFlags().MarkHidden(memprofile)
cmd.PersistentFlags().MarkHidden(cpuprofile)
+ cli.bindWaitFlag(cmd, 0, &options.waitSecs)
}
type feedOptions struct {
@@ -47,6 +48,7 @@ type feedOptions struct {
summarySecs int
speedtestBytes int
speedtestSecs int
+ waitSecs int
memprofile string
cpuprofile string
@@ -92,11 +94,11 @@ $ cat docs.jsonl | vespa feed -`,
return err
},
}
- addFeedFlags(cmd, &options)
+ addFeedFlags(cli, cmd, &options)
return cmd
}
-func createServices(n int, timeout time.Duration, cli *CLI) ([]util.HTTPClient, string, error) {
+func createServices(n int, timeout time.Duration, waitSecs int, cli *CLI) ([]util.HTTPClient, string, error) {
if n < 1 {
return nil, "", fmt.Errorf("need at least one client")
}
@@ -107,7 +109,7 @@ func createServices(n int, timeout time.Duration, cli *CLI) ([]util.HTTPClient,
services := make([]util.HTTPClient, 0, n)
baseURL := ""
for i := 0; i < n; i++ {
- service, err := cli.service(target, vespa.DocumentService, 0, cli.config.cluster())
+ service, err := cli.service(target, vespa.DocumentService, 0, cli.config.cluster(), time.Duration(waitSecs)*time.Second)
if err != nil {
return nil, "", err
}
@@ -201,7 +203,7 @@ func enqueueAndWait(files []string, dispatcher *document.Dispatcher, options fee
func feed(files []string, options feedOptions, cli *CLI) error {
timeout := time.Duration(options.timeoutSecs) * time.Second
- clients, baseURL, err := createServices(options.connections, timeout, cli)
+ clients, baseURL, err := createServices(options.connections, timeout, options.waitSecs, cli)
if err != nil {
return err
}
diff --git a/client/go/internal/cli/cmd/prod.go b/client/go/internal/cli/cmd/prod.go
index 6daa8db6e81..14fbae68b17 100644
--- a/client/go/internal/cli/cmd/prod.go
+++ b/client/go/internal/cli/cmd/prod.go
@@ -142,10 +142,7 @@ $ vespa prod deploy`,
if err := verifyTests(cli, pkg); err != nil {
return err
}
- opts, err := cli.createDeploymentOptions(pkg, target)
- if err != nil {
- return err
- }
+ opts := vespa.DeploymentOptions{ApplicationPackage: pkg, Target: target}
if err := maybeCopyCertificate(copyCert, true, cli, target, pkg); err != nil {
return err
}
@@ -405,6 +402,6 @@ func verifyTest(cli *CLI, testsParent string, suite string, required bool) error
}
return nil
}
- _, _, err = runTests(cli, testDirectory, true)
+ _, _, err = runTests(cli, testDirectory, true, 0)
return err
}
diff --git a/client/go/internal/cli/cmd/query.go b/client/go/internal/cli/cmd/query.go
index a14e2d51036..a5b35052b11 100644
--- a/client/go/internal/cli/cmd/query.go
+++ b/client/go/internal/cli/cmd/query.go
@@ -24,6 +24,7 @@ func newQueryCmd(cli *CLI) *cobra.Command {
var (
printCurl bool
queryTimeoutSecs int
+ waitSecs int
)
cmd := &cobra.Command{
Use: "query query-parameters",
@@ -38,11 +39,12 @@ can be set by the syntax [parameter-name]=[value].`,
SilenceUsage: true,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
- return query(cli, args, queryTimeoutSecs, printCurl)
+ return query(cli, args, queryTimeoutSecs, waitSecs, printCurl)
},
}
cmd.PersistentFlags().BoolVarP(&printCurl, "verbose", "v", false, "Print the equivalent curl command for the query")
cmd.Flags().IntVarP(&queryTimeoutSecs, "timeout", "T", 10, "Timeout for the query in seconds")
+ cli.bindWaitFlag(cmd, 0, &waitSecs)
return cmd
}
@@ -57,12 +59,12 @@ func printCurl(stderr io.Writer, url string, service *vespa.Service) error {
return err
}
-func query(cli *CLI, arguments []string, timeoutSecs int, curl bool) error {
+func query(cli *CLI, arguments []string, timeoutSecs, waitSecs int, curl bool) error {
target, err := cli.target(targetOptions{})
if err != nil {
return err
}
- service, err := cli.service(target, vespa.QueryService, 0, cli.config.cluster())
+ service, err := cli.service(target, vespa.QueryService, 0, cli.config.cluster(), time.Duration(waitSecs)*time.Second)
if err != nil {
return err
}
diff --git a/client/go/internal/cli/cmd/root.go b/client/go/internal/cli/cmd/root.go
index c6742d74f3e..ad42ea588b0 100644
--- a/client/go/internal/cli/cmd/root.go
+++ b/client/go/internal/cli/cmd/root.go
@@ -31,7 +31,6 @@ const (
clusterFlag = "cluster"
zoneFlag = "zone"
targetFlag = "target"
- waitFlag = "wait"
colorFlag = "color"
quietFlag = "quiet"
)
@@ -202,7 +201,6 @@ func (c *CLI) configureFlags() map[string]*pflag.Flag {
instance string
cluster string
zone string
- waitSecs int
color string
quiet bool
)
@@ -211,7 +209,6 @@ func (c *CLI) configureFlags() map[string]*pflag.Flag {
c.cmd.PersistentFlags().StringVarP(&instance, instanceFlag, "i", "", "The instance of the application to use")
c.cmd.PersistentFlags().StringVarP(&cluster, clusterFlag, "C", "", "The container cluster to use. This is only required for applications with multiple clusters")
c.cmd.PersistentFlags().StringVarP(&zone, zoneFlag, "z", "", "The zone to use. This defaults to a dev zone")
- c.cmd.PersistentFlags().IntVarP(&waitSecs, waitFlag, "w", 0, "Number of seconds to wait for a service to become ready")
c.cmd.PersistentFlags().StringVarP(&color, colorFlag, "c", "auto", `Whether to use colors in output. Must be "auto", "never", or "always"`)
c.cmd.PersistentFlags().BoolVarP(&quiet, quietFlag, "q", false, "Print only errors")
flags := make(map[string]*pflag.Flag)
@@ -280,6 +277,14 @@ func (c *CLI) configureCommands() {
rootCmd.AddCommand(newFeedCmd(c)) // feed
}
+func (c *CLI) bindWaitFlag(cmd *cobra.Command, defaultSecs int, value *int) {
+ desc := "Number of seconds to wait for a service to become ready. 0 to disable"
+ if defaultSecs == 0 {
+ desc += " (default 0)"
+ }
+ cmd.PersistentFlags().IntVarP(value, "wait", "w", defaultSecs, desc)
+}
+
func (c *CLI) printErr(err error, hints ...string) {
fmt.Fprintln(c.Stderr, color.RedString("Error:"), err)
for _, hint := range hints {
@@ -502,11 +507,7 @@ func (c *CLI) system(targetType string) (vespa.System, error) {
// service returns the service of given name located at target. If non-empty, cluster specifies a cluster to query. This
// function blocks according to the wait period configured in this CLI. The parameter sessionOrRunID specifies either
// the session ID (local target) or run ID (cloud target) to wait for.
-func (c *CLI) service(target vespa.Target, name string, sessionOrRunID int64, cluster string) (*vespa.Service, error) {
- timeout, err := c.config.timeout()
- if err != nil {
- return nil, err
- }
+func (c *CLI) service(target vespa.Target, name string, sessionOrRunID int64, cluster string, timeout time.Duration) (*vespa.Service, error) {
if timeout > 0 {
log.Printf("Waiting up to %s for %s service to become available ...", color.CyanString(timeout.String()), color.CyanString(name))
}
@@ -521,18 +522,6 @@ func (c *CLI) service(target vespa.Target, name string, sessionOrRunID int64, cl
return s, nil
}
-func (c *CLI) createDeploymentOptions(pkg vespa.ApplicationPackage, target vespa.Target) (vespa.DeploymentOptions, error) {
- timeout, err := c.config.timeout()
- if err != nil {
- return vespa.DeploymentOptions{}, err
- }
- return vespa.DeploymentOptions{
- ApplicationPackage: pkg,
- Target: target,
- Timeout: timeout,
- }, nil
-}
-
// isCI returns true if running inside a continuous integration environment.
func (c *CLI) isCI() bool {
_, ok := c.Environment["CI"]
diff --git a/client/go/internal/cli/cmd/status.go b/client/go/internal/cli/cmd/status.go
index ab98a4da160..6570aeff448 100644
--- a/client/go/internal/cli/cmd/status.go
+++ b/client/go/internal/cli/cmd/status.go
@@ -7,6 +7,7 @@ package cmd
import (
"fmt"
"log"
+ "time"
"github.com/fatih/color"
"github.com/spf13/cobra"
@@ -14,7 +15,8 @@ import (
)
func newStatusCmd(cli *CLI) *cobra.Command {
- return &cobra.Command{
+ var waitSecs int
+ cmd := &cobra.Command{
Use: "status",
Short: "Verify that a service is ready to use (query by default)",
Example: `$ vespa status query`,
@@ -22,13 +24,16 @@ func newStatusCmd(cli *CLI) *cobra.Command {
SilenceUsage: true,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
- return printServiceStatus(cli, vespa.QueryService)
+ return printServiceStatus(cli, vespa.QueryService, waitSecs)
},
}
+ cli.bindWaitFlag(cmd, 0, &waitSecs)
+ return cmd
}
func newStatusQueryCmd(cli *CLI) *cobra.Command {
- return &cobra.Command{
+ var waitSecs int
+ cmd := &cobra.Command{
Use: "query",
Short: "Verify that the query service is ready to use (default)",
Example: `$ vespa status query`,
@@ -36,13 +41,16 @@ func newStatusQueryCmd(cli *CLI) *cobra.Command {
SilenceUsage: true,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
- return printServiceStatus(cli, vespa.QueryService)
+ return printServiceStatus(cli, vespa.QueryService, waitSecs)
},
}
+ cli.bindWaitFlag(cmd, 0, &waitSecs)
+ return cmd
}
func newStatusDocumentCmd(cli *CLI) *cobra.Command {
- return &cobra.Command{
+ var waitSecs int
+ cmd := &cobra.Command{
Use: "document",
Short: "Verify that the document service is ready to use",
Example: `$ vespa status document`,
@@ -50,13 +58,16 @@ func newStatusDocumentCmd(cli *CLI) *cobra.Command {
SilenceUsage: true,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
- return printServiceStatus(cli, vespa.DocumentService)
+ return printServiceStatus(cli, vespa.DocumentService, waitSecs)
},
}
+ cli.bindWaitFlag(cmd, 0, &waitSecs)
+ return cmd
}
func newStatusDeployCmd(cli *CLI) *cobra.Command {
- return &cobra.Command{
+ var waitSecs int
+ cmd := &cobra.Command{
Use: "deploy",
Short: "Verify that the deploy service is ready to use",
Example: `$ vespa status deploy`,
@@ -64,26 +75,25 @@ func newStatusDeployCmd(cli *CLI) *cobra.Command {
SilenceUsage: true,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
- return printServiceStatus(cli, vespa.DeployService)
+ return printServiceStatus(cli, vespa.DeployService, waitSecs)
},
}
+ cli.bindWaitFlag(cmd, 0, &waitSecs)
+ return cmd
}
-func printServiceStatus(cli *CLI, name string) error {
+func printServiceStatus(cli *CLI, name string, waitSecs int) error {
t, err := cli.target(targetOptions{})
if err != nil {
return err
}
cluster := cli.config.cluster()
- s, err := cli.service(t, name, 0, cluster)
+ s, err := cli.service(t, name, 0, cluster, 0)
if err != nil {
return err
}
- timeout, err := cli.config.timeout()
- if err != nil {
- return err
- }
- status, err := s.Wait(timeout)
+ // Wait explicitly
+ status, err := s.Wait(time.Duration(waitSecs) * time.Second)
clusterPart := ""
if cluster != "" {
clusterPart = fmt.Sprintf(" named %s", color.CyanString(cluster))
diff --git a/client/go/internal/cli/cmd/test.go b/client/go/internal/cli/cmd/test.go
index 8c4501e2870..abee760efbb 100644
--- a/client/go/internal/cli/cmd/test.go
+++ b/client/go/internal/cli/cmd/test.go
@@ -26,6 +26,7 @@ import (
)
func newTestCmd(cli *CLI) *cobra.Command {
+ var waitSecs int
testCmd := &cobra.Command{
Use: "test test-directory-or-file",
Short: "Run a test suite, or a single test",
@@ -40,7 +41,7 @@ $ vespa test src/test/application/tests/system-test/feed-and-query.json`,
DisableAutoGenTag: true,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
- count, failed, err := runTests(cli, args[0], false)
+ count, failed, err := runTests(cli, args[0], false, waitSecs)
if err != nil {
return err
}
@@ -64,10 +65,11 @@ $ vespa test src/test/application/tests/system-test/feed-and-query.json`,
}
},
}
+ cli.bindWaitFlag(testCmd, 0, &waitSecs)
return testCmd
}
-func runTests(cli *CLI, rootPath string, dryRun bool) (int, []string, error) {
+func runTests(cli *CLI, rootPath string, dryRun bool, waitSecs int) (int, []string, error) {
count := 0
failed := make([]string, 0)
if stat, err := os.Stat(rootPath); err != nil {
@@ -86,7 +88,7 @@ func runTests(cli *CLI, rootPath string, dryRun bool) (int, []string, error) {
fmt.Fprintln(cli.Stdout, "")
previousFailed = false
}
- failure, err := runTest(testPath, context)
+ failure, err := runTest(testPath, context, waitSecs)
if err != nil {
return 0, nil, err
}
@@ -98,7 +100,7 @@ func runTests(cli *CLI, rootPath string, dryRun bool) (int, []string, error) {
}
}
} else if strings.HasSuffix(stat.Name(), ".json") {
- failure, err := runTest(rootPath, testContext{testsPath: filepath.Dir(rootPath), dryRun: dryRun, cli: cli})
+ failure, err := runTest(rootPath, testContext{testsPath: filepath.Dir(rootPath), dryRun: dryRun, cli: cli}, waitSecs)
if err != nil {
return 0, nil, err
}
@@ -114,7 +116,7 @@ func runTests(cli *CLI, rootPath string, dryRun bool) (int, []string, error) {
}
// Runs the test at the given path, and returns the specified test name if the test fails
-func runTest(testPath string, context testContext) (string, error) {
+func runTest(testPath string, context testContext, waitSecs int) (string, error) {
var test test
testBytes, err := os.ReadFile(testPath)
if err != nil {
@@ -147,7 +149,7 @@ func runTest(testPath string, context testContext) (string, error) {
if step.Name != "" {
stepName += ": " + step.Name
}
- failure, longFailure, err := verify(step, test.Defaults.Cluster, defaultParameters, context)
+ failure, longFailure, err := verify(step, test.Defaults.Cluster, defaultParameters, context, waitSecs)
if err != nil {
fmt.Fprintln(context.cli.Stderr)
return "", errHint(fmt.Errorf("error in %s: %w", stepName, err), "See https://docs.vespa.ai/en/reference/testing")
@@ -170,7 +172,7 @@ func runTest(testPath string, context testContext) (string, error) {
}
// Asserts specified response is obtained for request, or returns a failure message, or an error if this fails
-func verify(step step, defaultCluster string, defaultParameters map[string]string, context testContext) (string, string, error) {
+func verify(step step, defaultCluster string, defaultParameters map[string]string, context testContext, waitSecs int) (string, string, error) {
requestBody, err := getBody(step.Request.BodyRaw, context.testsPath)
if err != nil {
return "", "", err
@@ -214,7 +216,7 @@ func verify(step step, defaultCluster string, defaultParameters map[string]strin
if err != nil {
return "", "", err
}
- service, err = target.Service(vespa.QueryService, 0, 0, cluster)
+ service, err = target.Service(vespa.QueryService, time.Duration(waitSecs)*time.Second, 0, cluster)
if err != nil {
return "", "", err
}
diff --git a/client/go/internal/cli/cmd/visit.go b/client/go/internal/cli/cmd/visit.go
index a588474bd2b..302857bc7cd 100644
--- a/client/go/internal/cli/cmd/visit.go
+++ b/client/go/internal/cli/cmd/visit.go
@@ -35,6 +35,7 @@ type visitArgs struct {
sliceId int
bucketSpace string
bucketSpaces []string
+ waitSecs int
cli *CLI
}
@@ -107,7 +108,7 @@ $ vespa visit --field-set "[id]" # list document IDs
if !result.Success {
return fmt.Errorf("argument error: %s", result.Message)
}
- service, err := documentService(cli)
+ service, err := documentService(cli, vArgs.waitSecs)
if err != nil {
return err
}
@@ -135,6 +136,7 @@ $ vespa visit --field-set "[id]" # list document IDs
cmd.Flags().IntVar(&vArgs.sliceId, "slice-id", -1, `The number of the slice this visit invocation should fetch`)
cmd.Flags().IntVar(&vArgs.slices, "slices", -1, `Split the document corpus into this number of independent slices`)
cmd.Flags().StringSliceVar(&vArgs.bucketSpaces, "bucket-space", []string{"global", "default"}, `"default" or "global" bucket space`)
+ cli.bindWaitFlag(cmd, 0, &vArgs.waitSecs)
return cmd
}
diff --git a/client/go/internal/cli/cmd/visit_test.go b/client/go/internal/cli/cmd/visit_test.go
index 9bb8f61554a..f85fb739370 100644
--- a/client/go/internal/cli/cmd/visit_test.go
+++ b/client/go/internal/cli/cmd/visit_test.go
@@ -96,7 +96,7 @@ func withMockClient(t *testing.T, prepCli func(*mock.HTTPClient), runOp func(*ve
prepCli(client)
cli, _, _ := newTestCLI(t)
cli.httpClient = client
- service, _ := documentService(cli)
+ service, _ := documentService(cli, 0)
runOp(service)
return client.LastRequest
}