aboutsummaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/go/internal/cli/cmd/api_key.go7
-rw-r--r--client/go/internal/cli/cmd/deploy.go3
-rw-r--r--client/go/internal/cli/cmd/deploy_test.go2
-rw-r--r--client/go/internal/cli/cmd/status.go5
-rw-r--r--client/go/internal/cli/cmd/status_test.go26
-rw-r--r--client/go/internal/cli/cmd/testutil_test.go1
-rw-r--r--client/go/internal/cli/cmd/waiter.go14
-rw-r--r--client/go/internal/vespa/target_cloud.go4
8 files changed, 40 insertions, 22 deletions
diff --git a/client/go/internal/cli/cmd/api_key.go b/client/go/internal/cli/cmd/api_key.go
index 938b6623b0b..4288c9fb029 100644
--- a/client/go/internal/cli/cmd/api_key.go
+++ b/client/go/internal/cli/cmd/api_key.go
@@ -21,8 +21,9 @@ func newAPIKeyCmd(cli *CLI) *cobra.Command {
Short: "Create a new developer key for headless authentication with Vespa Cloud control plane",
Long: `Create a new developer key for headless authentication with Vespa Cloud control plane
-A developer key is intended for headless communication with the Vespa Cloud
-control plane. For example when deploying from a continuous integration system.
+A developer key is a tenant-wide secret, intended for headless communication
+with the Vespa Cloud control plane. For example when deploying from a continuous
+integration system.
The developer key will be stored in the Vespa CLI home directory
(see 'vespa help config'). Other commands will then automatically load the developer
@@ -43,7 +44,7 @@ Note that when overriding the developer key through environment variables,
that key will always be used. It's not possible to specify a tenant-specific
key through the environment.
-Read more in https://cloud.vespa.ai/en/security/guide`,
+See https://cloud.vespa.ai/en/security/guide for more details about developer keys.`,
Example: "$ vespa auth api-key -a my-tenant.my-app.my-instance",
DisableAutoGenTag: true,
SilenceUsage: true,
diff --git a/client/go/internal/cli/cmd/deploy.go b/client/go/internal/cli/cmd/deploy.go
index fac779c8241..19c48f942a6 100644
--- a/client/go/internal/cli/cmd/deploy.go
+++ b/client/go/internal/cli/cmd/deploy.go
@@ -190,6 +190,9 @@ func waitForVespaReady(target vespa.Target, sessionOrRunID int64, waiter *Waiter
if fastWait || hasTimeout {
// Wait for deployment convergence
if _, err := waiter.Deployment(target, sessionOrRunID); err != nil {
+ if fastWait && errors.Is(err, vespa.ErrWaitTimeout) {
+ return nil // // Do not report fast wait timeout as an error
+ }
return err
}
// Wait for healthy services where we expect them to be reachable (cloud and local). When using a custom target,
diff --git a/client/go/internal/cli/cmd/deploy_test.go b/client/go/internal/cli/cmd/deploy_test.go
index 3f71a59e682..1c74c1364ca 100644
--- a/client/go/internal/cli/cmd/deploy_test.go
+++ b/client/go/internal/cli/cmd/deploy_test.go
@@ -107,7 +107,7 @@ func TestDeployCloudFastWait(t *testing.T) {
httpClient.NextResponseString(200, `ok`)
httpClient.NextResponseString(200, `{"active": false, "status": "unsuccesful"}`)
require.NotNil(t, cli.Run("deploy", pkgDir))
- assert.Equal(t, stderr.String(), "Error: deployment run 0 not yet complete after waiting up to 2s: aborting wait: deployment failed: run 0 ended with unsuccessful status: unsuccesful\n")
+ assert.Equal(t, stderr.String(), "Error: deployment run 0 not yet complete after waiting up to 3s: aborting wait: deployment failed: run 0 ended with unsuccessful status: unsuccesful\n")
assert.True(t, httpClient.Consumed())
// Deployment which is running does not return error
diff --git a/client/go/internal/cli/cmd/status.go b/client/go/internal/cli/cmd/status.go
index dff0c2d24c6..98f40b5f956 100644
--- a/client/go/internal/cli/cmd/status.go
+++ b/client/go/internal/cli/cmd/status.go
@@ -177,9 +177,12 @@ $ vespa status deployment -t local [session-id] --wait 600
waiter := cli.waiter(time.Duration(waitSecs)*time.Second, cmd)
id, err := waiter.Deployment(t, wantedID)
if err != nil {
+ if errors.Is(err, vespa.ErrWaitTimeout) && t.IsCloud() {
+ cli.printInfo("Deployment is still running. See ", color.CyanString(t.Deployment().System.ConsoleRunURL(t.Deployment(), id)), " for more details")
+ }
var hints []string
if waiter.Timeout == 0 && !errors.Is(err, vespa.ErrDeployment) {
- hints = []string{"Consider using the --wait flag to wait for completion"}
+ hints = []string{"Consider using the --wait flag to increase the wait period", "--wait 120 will make this command wait for completion up to 2 minutes"}
}
return ErrCLI{Status: 1, warn: true, hints: hints, error: err}
}
diff --git a/client/go/internal/cli/cmd/status_test.go b/client/go/internal/cli/cmd/status_test.go
index 6db27fd2778..5ccac420c4e 100644
--- a/client/go/internal/cli/cmd/status_test.go
+++ b/client/go/internal/cli/cmd/status_test.go
@@ -122,13 +122,13 @@ func TestStatusLocalDeployment(t *testing.T) {
resp.Body = []byte(`{"currentGeneration": 42, "converged": false}`)
client.NextResponse(resp)
assert.NotNil(t, cli.Run("status", "deployment"))
- assert.Equal(t, "Warning: deployment not converged on latest generation: wait deadline reached\nHint: Consider using the --wait flag to wait for completion\n", stderr.String())
+ assert.Equal(t, "Warning: deployment not converged on latest generation: wait deadline reached\nHint: Consider using the --wait flag to increase the wait period\nHint: --wait 120 will make this command wait for completion up to 2 minutes\n", stderr.String())
// Explicit generation
stderr.Reset()
client.NextResponse(resp)
assert.NotNil(t, cli.Run("status", "deployment", "41"))
- assert.Equal(t, "Warning: deployment not converged on generation 41: wait deadline reached\nHint: Consider using the --wait flag to wait for completion\n", stderr.String())
+ assert.Equal(t, "Warning: deployment not converged on generation 41: wait deadline reached\nHint: Consider using the --wait flag to increase the wait period\nHint: --wait 120 will make this command wait for completion up to 2 minutes\n", stderr.String())
}
func TestStatusCloudDeployment(t *testing.T) {
@@ -141,6 +141,24 @@ func TestStatusCloudDeployment(t *testing.T) {
stdout.Reset()
client := &mock.HTTPClient{}
cli.httpClient = client
+ // Deployment in progress, with implicit fast wait
+ client.NextResponse(mock.HTTPResponse{
+ URI: "/application/v4/tenant/t1/application/a1/instance/i1/job/dev-us-north-1?limit=1",
+ Status: 200,
+ Body: []byte(`{"runs": [{"id": 1337}]}`),
+ })
+ client.NextResponse(mock.HTTPResponse{
+ URI: "/application/v4/tenant/t1/application/a1/instance/i1/job/dev-us-north-1/run/1337?after=-1",
+ Status: 200,
+ Body: []byte(`{"active": true, "status": "running"}`),
+ })
+ assert.NotNil(t, cli.Run("status", "deployment"))
+ assert.Equal(t, `Deployment is still running. See https://console.vespa-cloud.com/tenant/t1/application/a1/dev/instance/i1/job/dev-us-north-1/run/1337 for more details
+Warning: deployment run 1337 not yet complete after waiting up to 3s: wait deadline reached
+Hint: Consider using the --wait flag to increase the wait period
+Hint: --wait 120 will make this command wait for completion up to 2 minutes
+`, stderr.String())
+ assert.Equal(t, "", stdout.String())
// Latest run
client.NextResponse(mock.HTTPResponse{
URI: "/application/v4/tenant/t1/application/a1/instance/i1/job/dev-us-north-1?limit=1",
@@ -152,12 +170,14 @@ func TestStatusCloudDeployment(t *testing.T) {
Status: 200,
Body: []byte(`{"active": false, "status": "success"}`),
})
+ stderr.Reset()
+ stdout.Reset()
assert.Nil(t, cli.Run("status", "deployment"))
assert.Equal(t, "", stderr.String())
assert.Equal(t,
"Deployment run 1337 has completed\nSee https://console.vespa-cloud.com/tenant/t1/application/a1/dev/instance/i1/job/dev-us-north-1/run/1337 for more details\n",
stdout.String())
- // Explicit run with waiting
+ // Explicit run ID and wait period
client.NextResponse(mock.HTTPResponse{
URI: "/application/v4/tenant/t1/application/a1/instance/i1/job/dev-us-north-1/run/42?after=-1",
Status: 200,
diff --git a/client/go/internal/cli/cmd/testutil_test.go b/client/go/internal/cli/cmd/testutil_test.go
index dbeb281a4a8..1aaac8e44b0 100644
--- a/client/go/internal/cli/cmd/testutil_test.go
+++ b/client/go/internal/cli/cmd/testutil_test.go
@@ -40,6 +40,7 @@ func newTestCLI(t *testing.T, envVars ...string) (*CLI, *bytes.Buffer, *bytes.Bu
cli.ztsFactory = func(httpClient httputil.Client, domain, url string) (vespa.Authenticator, error) {
return &mockAuthenticator{}, nil
}
+ cli.retryInterval = time.Hour // Disable waiting in tests. Waiting is short-circuited if --wait < retryInterval
return cli, &stdout, &stderr
}
diff --git a/client/go/internal/cli/cmd/waiter.go b/client/go/internal/cli/cmd/waiter.go
index 8a25e18cd1e..9127927e7ad 100644
--- a/client/go/internal/cli/cmd/waiter.go
+++ b/client/go/internal/cli/cmd/waiter.go
@@ -2,7 +2,6 @@
package cmd
import (
- "errors"
"fmt"
"time"
@@ -98,16 +97,7 @@ func (w *Waiter) Deployment(target vespa.Target, wantedID int64) (int64, error)
} else if fastWait {
// If --wait is not explicitly given, we always wait a few seconds in Cloud to catch fast failures, e.g.
// invalid application package
- timeout = 2 * time.Second
+ timeout = 3 * time.Second
}
- id, err := target.AwaitDeployment(wantedID, timeout)
- if errors.Is(err, vespa.ErrWaitTimeout) {
- if fastWait {
- return id, nil // Do not report fast wait timeout as an error
- }
- if target.IsCloud() {
- w.cli.printInfo("Timed out waiting for deployment to converge. See ", color.CyanString(target.Deployment().System.ConsoleRunURL(target.Deployment(), wantedID)), " for more details")
- }
- }
- return id, err
+ return target.AwaitDeployment(wantedID, timeout)
}
diff --git a/client/go/internal/vespa/target_cloud.go b/client/go/internal/vespa/target_cloud.go
index 05d6bdd224e..d410a9103ea 100644
--- a/client/go/internal/vespa/target_cloud.go
+++ b/client/go/internal/vespa/target_cloud.go
@@ -259,10 +259,10 @@ func (t *cloudTarget) AwaitDeployment(runID int64, timeout time.Duration) (int64
}
_, err = deployServiceWait(t, jobSuccessFunc, requestFunc, timeout, t.retryInterval)
if err != nil {
- return 0, fmt.Errorf("deployment run %d not yet complete%s: %w", runID, waitDescription(timeout), err)
+ return runID, fmt.Errorf("deployment run %d not yet complete%s: %w", runID, waitDescription(timeout), err)
}
if !success {
- return 0, fmt.Errorf("deployment run %d not yet complete%s", runID, waitDescription(timeout))
+ return runID, fmt.Errorf("deployment run %d not yet complete%s", runID, waitDescription(timeout))
}
return runID, nil
}