diff options
author | Jon Bratseth <bratseth@gmail.com> | 2021-08-31 11:05:32 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2021-08-31 11:05:32 +0200 |
commit | 2ded6dbdc3cab62862c1ce448c1903cab9182916 (patch) | |
tree | 2f76136936777162b30530dcd36ee42d3c7ab9db /client | |
parent | 7f4537e1cad5ce9b0e1031697af3680cd348a8e0 (diff) |
Extract application package error
Diffstat (limited to 'client')
-rw-r--r-- | client/go/cmd/deploy_test.go | 29 | ||||
-rw-r--r-- | client/go/cmd/document.go | 3 | ||||
-rw-r--r-- | client/go/vespa/deploy.go | 25 |
3 files changed, 48 insertions, 9 deletions
diff --git a/client/go/cmd/deploy_test.go b/client/go/cmd/deploy_test.go index fdd1d9f5613..d4fddf11f99 100644 --- a/client/go/cmd/deploy_test.go +++ b/client/go/cmd/deploy_test.go @@ -54,8 +54,27 @@ func TestDeployApplicationDirectoryWithPomAndEmptyTarget(t *testing.T) { executeCommand(t, client, []string{"deploy", "testdata/applications/withEmptyTarget"}, []string{})) } -func TestDeployApplicationPackageError(t *testing.T) { - assertApplicationPackageError(t, 401, "Application package error") +func TestDeployApplicationPackageErrorWithUnexpectedNonJson(t *testing.T) { + assertApplicationPackageError(t, 401, + "Raw text error", + "Raw text error") +} + +func TestDeployApplicationPackageErrorWithUnexpectedJson(t *testing.T) { + assertApplicationPackageError(t, 401, + `{ + "some-unexpected-json": "Invalid XML, error in services.xml: element \"nosuch\" not allowed here" +}`, + `{"some-unexpected-json": "Invalid XML, error in services.xml: element \"nosuch\" not allowed here"}`) +} + +func TestDeployApplicationPackageErrorWithExpectedFormat(t *testing.T) { + assertApplicationPackageError(t, 400, + "Invalid XML, error in services.xml:\nelement \"nosuch\" not allowed here", + `{ + "error-code": "INVALID_APPLICATION_PACKAGE", + "message": "Invalid XML, error in services.xml: element \"nosuch\" not allowed here\n" + }`) } func TestDeployError(t *testing.T) { @@ -81,10 +100,10 @@ func assertDeployRequestMade(target string, client *mockHttpClient, t *testing.T assert.Equal(t, "PK\x03\x04\x14\x00\b", string(buf)) } -func assertApplicationPackageError(t *testing.T, status int, errorMessage string) { - client := &mockHttpClient{nextStatus: status, nextBody: errorMessage} +func assertApplicationPackageError(t *testing.T, status int, expectedMessage string, returnBody string) { + client := &mockHttpClient{nextStatus: status, nextBody: returnBody} assert.Equal(t, - "Error: Invalid application package (Status "+strconv.Itoa(status)+"):\n"+errorMessage+"\n", + "Error: Invalid application package (Status "+strconv.Itoa(status)+")\n\n"+expectedMessage+"\n", executeCommand(t, client, []string{"deploy", "testdata/applications/withTarget/target/application.zip"}, []string{})) } diff --git a/client/go/cmd/document.go b/client/go/cmd/document.go index 9aa50b60f56..71114fc8df6 100644 --- a/client/go/cmd/document.go +++ b/client/go/cmd/document.go @@ -70,7 +70,8 @@ func post(documentId string, jsonFile string) { fileReader, fileError := os.Open(jsonFile) if fileError != nil { - log.Printf("Could not open file at %s: %s", color.Cyan(jsonFile), fileError) + log.Print(color.Red("Error: "), "Could not open file '", color.Cyan(jsonFile), "'") + log.Print(color.Brown(fileError)) return } diff --git a/client/go/vespa/deploy.go b/client/go/vespa/deploy.go index 037c92b5458..9955c3dfbff 100644 --- a/client/go/vespa/deploy.go +++ b/client/go/vespa/deploy.go @@ -6,6 +6,8 @@ package vespa import ( "archive/zip" + "bytes" + "encoding/json" "errors" "fmt" "io" @@ -126,7 +128,7 @@ func Prepare(deployment Deployment) (string, error) { if deployment.IsCloud() { return "", fmt.Errorf("%s: prepare is not supported", deployment) } - // TODO: This doesn't work. A session ID must be explicitly created and then passed to the prepare call + // TODO: Save session id in .vespa // https://docs.vespa.ai/en/cloudconfig/deploy-rest-api-v2.html u, err := url.Parse(deployment.TargetURL + "/application/v2/tenant/default/prepare") if err != nil { @@ -139,7 +141,7 @@ func Activate(deployment Deployment) (string, error) { if deployment.IsCloud() { return "", fmt.Errorf("%s: activate is not supported", deployment) } - // TODO: This doesn't work. A session ID must be explicitly created and then passed to the activate call + // TODO: Look up session id in .vespa // https://docs.vespa.ai/en/cloudconfig/deploy-rest-api-v2.html u, err := url.Parse(deployment.TargetURL + "/application/v2/tenant/default/activate") if err != nil { @@ -210,7 +212,7 @@ func postApplicationPackage(url *url.URL, zipReader io.Reader) error { defer response.Body.Close() if response.StatusCode/100 == 4 { - return fmt.Errorf("Invalid application package (%s):\n%s", response.Status, util.ReaderToJSON(response.Body)) + return fmt.Errorf("Invalid application package (%s)\n\n%s", response.Status, extractError(response.Body)) } else if response.StatusCode != 200 { return fmt.Errorf("Error from %s at %s (%s):\n%s", strings.ToLower(serviceDescription), request.URL.Host, response.Status, util.ReaderToJSON(response.Body)) } @@ -270,3 +272,20 @@ func zipDir(dir string, destination string) error { } return filepath.Walk(dir, walker) } + +// Returns the error message in the given JSON, or the entire content if it could not be extracted +func extractError(reader io.Reader) string { + responseData := util.ReaderToBytes(reader) + var response map[string]interface{} + json.Unmarshal(responseData, &response) + if response["error-code"] == "INVALID_APPLICATION_PACKAGE" { + return strings.ReplaceAll(response["message"].(string), ": ", ":\n") + } else { + var prettyJSON bytes.Buffer + parseError := json.Indent(&prettyJSON, responseData, "", " ") + if parseError != nil { // Not JSON: Print plainly + return string(responseData) + } + return string(prettyJSON.Bytes()) + } +} |