summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2021-09-06 10:21:21 +0200
committerGitHub <noreply@github.com>2021-09-06 10:21:21 +0200
commit7c784391589e9ebc3d03531c99a32b2bd13b1971 (patch)
tree241af0b33e92c8167fb80e4220e7b4a6a7a5f34c /client
parent3dcba37979411b8d555c0f90308367ce6be7bfc1 (diff)
parent311783d7db166984ba1cc5fc2c023ed2b7015a9e (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.go2
-rw-r--r--client/go/cmd/document.go20
-rw-r--r--client/go/cmd/query.go12
-rw-r--r--client/go/util/http.go4
-rw-r--r--client/go/vespa/document.go43
-rw-r--r--client/go/vespa/target.go31
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