diff options
author | Jon Bratseth <bratseth@oath.com> | 2021-09-06 10:21:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-06 10:21:21 +0200 |
commit | 7c784391589e9ebc3d03531c99a32b2bd13b1971 (patch) | |
tree | 241af0b33e92c8167fb80e4220e7b4a6a7a5f34c /client | |
parent | 3dcba37979411b8d555c0f90308367ce6be7bfc1 (diff) | |
parent | 311783d7db166984ba1cc5fc2c023ed2b7015a9e (diff) |
Merge pull request #18972 from vespa-engine/mpolden/query-feed-cloud
Support cloud in vespa query/document
Diffstat (limited to 'client')
-rw-r--r-- | client/go/cmd/deploy.go | 2 | ||||
-rw-r--r-- | client/go/cmd/document.go | 20 | ||||
-rw-r--r-- | client/go/cmd/query.go | 12 | ||||
-rw-r--r-- | client/go/util/http.go | 4 | ||||
-rw-r--r-- | client/go/vespa/document.go | 43 | ||||
-rw-r--r-- | client/go/vespa/target.go | 31 |
6 files changed, 62 insertions, 50 deletions
diff --git a/client/go/cmd/deploy.go b/client/go/cmd/deploy.go index 6682891b97e..7d180775e24 100644 --- a/client/go/cmd/deploy.go +++ b/client/go/cmd/deploy.go @@ -60,7 +60,7 @@ has started but may not have completed.`, if err := vespa.Deploy(opts); err == nil { printSuccess("Deployed ", color.Cyan(pkg.Path)) if opts.IsCloud() { - log.Printf("\n\nUse %s for deployment status, or see", color.Cyan("vespa status")) + log.Printf("\nUse %s for deployment status, or see", color.Cyan("vespa status")) log.Print(color.Cyan(fmt.Sprintf("https://console.vespa.oath.cloud/tenant/%s/application/%s/dev/instance/%s", opts.Deployment.Application.Tenant, opts.Deployment.Application.Application, opts.Deployment.Application.Instance))) } } else { diff --git a/client/go/cmd/document.go b/client/go/cmd/document.go index e4591886511..bfa5efa8a9a 100644 --- a/client/go/cmd/document.go +++ b/client/go/cmd/document.go @@ -37,7 +37,7 @@ should be used instead of this.`, Example: `$ vespa document src/test/resources/A-Head-Full-of-Dreams.json`, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - printResult(vespa.Send(args[0], documentTarget()), false) + printResult(vespa.Send(args[0], documentService()), false) }, } @@ -52,9 +52,9 @@ If the document id is specified both as an argument and in the file the argument $ vespa document put id:mynamespace:music::a-head-full-of-dreams src/test/resources/A-Head-Full-of-Dreams.json`, Run: func(cmd *cobra.Command, args []string) { if len(args) == 1 { - printResult(vespa.Put("", args[0], documentTarget()), false) + printResult(vespa.Put("", args[0], documentService()), false) } else { - printResult(vespa.Put(args[0], args[1], documentTarget()), false) + printResult(vespa.Put(args[0], args[1], documentService()), false) } }, } @@ -69,9 +69,9 @@ If the document id is specified both as an argument and in the file the argument $ vespa document update id:mynamespace:music::a-head-full-of-dreams src/test/resources/A-Head-Full-of-Dreams.json`, Run: func(cmd *cobra.Command, args []string) { if len(args) == 1 { - printResult(vespa.Update("", args[0], documentTarget()), false) + printResult(vespa.Update("", args[0], documentService()), false) } else { - printResult(vespa.Update(args[0], args[1], documentTarget()), false) + printResult(vespa.Update(args[0], args[1], documentService()), false) } }, } @@ -86,9 +86,9 @@ If the document id is specified both as an argument and in the file the argument $ vespa document remove id:mynamespace:music::a-head-full-of-dreams`, Run: func(cmd *cobra.Command, args []string) { if strings.HasPrefix(args[0], "id:") { - printResult(vespa.RemoveId(args[0], documentTarget()), false) + printResult(vespa.RemoveId(args[0], documentService()), false) } else { - printResult(vespa.RemoveOperation(args[0], documentTarget()), false) + printResult(vespa.RemoveOperation(args[0], documentService()), false) } }, } @@ -98,13 +98,11 @@ var documentGetCmd = &cobra.Command{ Short: "Gets a document", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { - printResult(vespa.Get(args[0], documentTarget()), true) + printResult(vespa.Get(args[0], documentService()), true) }, } -func documentTarget() string { - return getService("document").BaseURL -} +func documentService() *vespa.Service { return getService("document") } func printResult(result util.OperationResult, payloadOnlyOnSuccess bool) { if !result.Success { diff --git a/client/go/cmd/query.go b/client/go/cmd/query.go index 1708aff45db..b270c1ed64b 100644 --- a/client/go/cmd/query.go +++ b/client/go/cmd/query.go @@ -22,7 +22,7 @@ func init() { var queryCmd = &cobra.Command{ Use: "query <query-parameters>", Short: "Issue a query to Vespa", - Example: `$ vespa query "yql=select from sources * where title contains 'foo';" hits=5`, + Example: `$ vespa query "yql=select * from sources * where title contains 'foo';" hits=5`, Long: `Issue a query to Vespa. Any parameter from https://docs.vespa.ai/en/reference/query-api-reference.html @@ -35,7 +35,8 @@ can be set by the syntax [parameter-name]=[value].`, } func query(arguments []string) { - url, _ := url.Parse(queryTarget() + "/search/") + service := getService("query") + url, _ := url.Parse(service.BaseURL + "/search/") urlQuery := url.Query() for i := 0; i < len(arguments); i++ { key, value := splitArg(arguments[i]) @@ -43,8 +44,7 @@ func query(arguments []string) { } url.RawQuery = urlQuery.Encode() - // TODO: Make this work for Vespa Cloud (pass certificate) - response, err := util.HttpDo(&http.Request{URL: url}, time.Second*10, "Container") + response, err := service.Do(&http.Request{URL: url}, time.Second*10) if err != nil { log.Print(color.Red("Error: "), "Request failed: ", err) return @@ -70,7 +70,3 @@ func splitArg(argument string) (string, string) { return argument[0:equalsIndex], argument[equalsIndex+1:] } } - -func queryTarget() string { - return getService("query").BaseURL -} diff --git a/client/go/util/http.go b/client/go/util/http.go index 5607e7dcdb7..4e524fa2d79 100644 --- a/client/go/util/http.go +++ b/client/go/util/http.go @@ -25,8 +25,8 @@ type defaultHttpClient struct { } func (c *defaultHttpClient) Do(request *http.Request, timeout time.Duration) (response *http.Response, error error) { - if c.client.Timeout != timeout { // Create a new client with the right timeout - c.client = &http.Client{Timeout: timeout} + if c.client.Timeout != timeout { // Set wanted timeout + c.client.Timeout = timeout } return c.client.Do(request) } diff --git a/client/go/vespa/document.go b/client/go/vespa/document.go index 25a57748bac..e737fdb87f2 100644 --- a/client/go/vespa/document.go +++ b/client/go/vespa/document.go @@ -17,24 +17,24 @@ import ( ) // Sends the operation given in the file -func Send(jsonFile string, target string) util.OperationResult { - return sendOperation("", jsonFile, target, anyOperation) +func Send(jsonFile string, service *Service) util.OperationResult { + return sendOperation("", jsonFile, service, anyOperation) } -func Put(documentId string, jsonFile string, target string) util.OperationResult { - return sendOperation(documentId, jsonFile, target, putOperation) +func Put(documentId string, jsonFile string, service *Service) util.OperationResult { + return sendOperation(documentId, jsonFile, service, putOperation) } -func Update(documentId string, jsonFile string, target string) util.OperationResult { - return sendOperation(documentId, jsonFile, target, updateOperation) +func Update(documentId string, jsonFile string, service *Service) util.OperationResult { + return sendOperation(documentId, jsonFile, service, updateOperation) } -func RemoveId(documentId string, target string) util.OperationResult { - return sendOperation(documentId, "", target, removeOperation) +func RemoveId(documentId string, service *Service) util.OperationResult { + return sendOperation(documentId, "", service, removeOperation) } -func RemoveOperation(jsonFile string, target string) util.OperationResult { - return sendOperation("", jsonFile, target, removeOperation) +func RemoveOperation(jsonFile string, service *Service) util.OperationResult { + return sendOperation("", jsonFile, service, removeOperation) } const ( @@ -44,7 +44,7 @@ const ( removeOperation string = "remove" ) -func sendOperation(documentId string, jsonFile string, target string, operation string) util.OperationResult { +func sendOperation(documentId string, jsonFile string, service *Service, operation string) util.OperationResult { header := http.Header{} header.Add("Content-Type", "application/json") @@ -82,9 +82,9 @@ func sendOperation(documentId string, jsonFile string, target string, operation return util.Failure("Invalid document id '" + documentId + "': " + documentPathError.Error()) } - url, urlParseError := url.Parse(target + "/document/v1/" + documentPath) + url, urlParseError := url.Parse(service.BaseURL + "/document/v1/" + documentPath) if urlParseError != nil { - return util.Failure("Invalid request path: '" + target + "/document/v1/" + documentPath + "': " + urlParseError.Error()) + return util.Failure("Invalid request path: '" + service.BaseURL + "/document/v1/" + documentPath + "': " + urlParseError.Error()) } request := &http.Request{ @@ -93,8 +93,7 @@ func sendOperation(documentId string, jsonFile string, target string, operation Header: header, Body: ioutil.NopCloser(bytes.NewReader(documentData)), } - serviceDescription := "Container (document API)" - response, err := util.HttpDo(request, time.Second*60, serviceDescription) + response, err := service.Do(request, time.Second*60) if response == nil { return util.Failure("Request failed: " + err.Error()) } @@ -105,7 +104,7 @@ func sendOperation(documentId string, jsonFile string, target string, operation } else if response.StatusCode/100 == 4 { return util.FailureWithPayload("Invalid document operation: "+response.Status, util.ReaderToJSON(response.Body)) } else { - return util.FailureWithPayload(serviceDescription+" at "+request.URL.Host+": "+response.Status, util.ReaderToJSON(response.Body)) + return util.FailureWithPayload(service.Description()+" at "+request.URL.Host+": "+response.Status, util.ReaderToJSON(response.Body)) } } @@ -133,24 +132,22 @@ func operationToHTTPMethod(operation string) string { panic("Unexpected document operation ''" + operation + "'") } -func Get(documentId string, target string) util.OperationResult { +func Get(documentId string, service *Service) util.OperationResult { documentPath, documentPathError := IdToURLPath(documentId) if documentPathError != nil { return util.Failure("Invalid document id '" + documentId + "': " + documentPathError.Error()) } - url, urlParseError := url.Parse(target + "/document/v1/" + documentPath) + url, urlParseError := url.Parse(service.BaseURL + "/document/v1/" + documentPath) if urlParseError != nil { - return util.Failure("Invalid request path: '" + target + "/document/v1/" + documentPath + "': " + urlParseError.Error()) + return util.Failure("Invalid request path: '" + service.BaseURL + "/document/v1/" + documentPath + "': " + urlParseError.Error()) } request := &http.Request{ URL: url, Method: "GET", } - serviceDescription := "Container (document API)" - // TODO: Make this work for Vespa Cloud (pass certificate) - response, err := util.HttpDo(request, time.Second*60, serviceDescription) + response, err := service.Do(request, time.Second*60) if response == nil { return util.Failure("Request failed: " + err.Error()) } @@ -161,6 +158,6 @@ func Get(documentId string, target string) util.OperationResult { } else if response.StatusCode/100 == 4 { return util.FailureWithPayload("Invalid document operation: "+response.Status, util.ReaderToJSON(response.Body)) } else { - return util.FailureWithPayload(serviceDescription+" at "+request.URL.Host+": "+response.Status, util.ReaderToJSON(response.Body)) + return util.FailureWithPayload(service.Description()+" at "+request.URL.Host+": "+response.Status, util.ReaderToJSON(response.Body)) } } diff --git a/client/go/vespa/target.go b/client/go/vespa/target.go index 1aa394835ff..61bfbe603a0 100644 --- a/client/go/vespa/target.go +++ b/client/go/vespa/target.go @@ -29,6 +29,7 @@ const ( type Service struct { BaseURL string Name string + description string certificate tls.Certificate } @@ -51,6 +52,14 @@ type customTarget struct { type localTarget struct{ targetType string } +// Do sends request to this service. Any required authentication happens automatically. +func (s *Service) Do(request *http.Request, timeout time.Duration) (*http.Response, error) { + if s.certificate.Certificate != nil { + util.ActiveHttpClient.UseCertificate(s.certificate) + } + return util.HttpDo(request, timeout, s.Description()) +} + // Wait polls the health check of this service until it succeeds or timeout passes. func (s *Service) Wait(timeout time.Duration) (int, error) { url := s.BaseURL @@ -67,10 +76,22 @@ func (s *Service) Wait(timeout time.Duration) (int, error) { return 0, err } okFunc := func(status int, response []byte) (string, bool) { return "", status/100 == 2 } - status, _, err := wait(okFunc, req, &s.certificate, timeout) + status, _, err := wait(okFunc, req, s.certificate, timeout) return status, err } +func (s *Service) Description() string { + switch s.Name { + case queryService: + return "Container (search API)" + case documentService: + return "Container (document API)" + case deployService: + return "Deploy API" + } + return fmt.Sprintf("No description of service %s", s.Name) +} + func (t *customTarget) Type() string { return t.targetType } func (t *customTarget) Service(name string) (*Service, error) { @@ -153,7 +174,7 @@ func (t *cloudTarget) DiscoverServices(timeout time.Duration) error { } return resp.Endpoints[0].URL, true } - _, endpoint, err := wait(endpointFunc, req, &t.keyPair, timeout) + _, endpoint, err := wait(endpointFunc, req, t.keyPair, timeout) if err != nil { return err } @@ -194,9 +215,9 @@ type deploymentResponse struct { type responseFunc func(status int, response []byte) (string, bool) -func wait(fn responseFunc, req *http.Request, certificate *tls.Certificate, timeout time.Duration) (int, string, error) { - if certificate != nil { - util.ActiveHttpClient.UseCertificate(*certificate) +func wait(fn responseFunc, req *http.Request, certificate tls.Certificate, timeout time.Duration) (int, string, error) { + if certificate.Certificate != nil { + util.ActiveHttpClient.UseCertificate(certificate) } var ( httpErr error |