diff options
Diffstat (limited to 'client/go/internal')
-rw-r--r-- | client/go/internal/cli/cmd/api_key.go | 7 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/deploy.go | 3 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/deploy_test.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/status.go | 5 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/status_test.go | 26 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/testutil_test.go | 1 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/waiter.go | 14 | ||||
-rw-r--r-- | client/go/internal/vespa/target_cloud.go | 4 |
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 } |