diff options
author | Martin Polden <mpolden@mpolden.no> | 2023-11-23 11:10:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-23 11:10:24 +0100 |
commit | 6f9b43ab5aeafa4bf52208a6ca606509d3edc076 (patch) | |
tree | 1eeacd63b87e734c249680b05b54ed141dae1e30 | |
parent | afde670ae04cd7e4645a180816a61c697d29698c (diff) | |
parent | 7815564d007624847fc0da6ee8ae0d412dd8d7df (diff) |
Merge pull request #29436 from vespa-engine/mpolden/verbose
Add verbose option to vespa visit
-rw-r--r-- | client/go/internal/admin/deploy/curl.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/api_key.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/cert.go | 4 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/config_test.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/deploy.go | 4 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/destroy.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/destroy_test.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/document.go | 49 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/document_test.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/log.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/login.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/logout.go | 2 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/prod.go | 4 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/root.go | 18 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/visit.go | 5 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/waiter.go | 2 | ||||
-rw-r--r-- | client/go/internal/curl/curl.go | 13 | ||||
-rw-r--r-- | client/go/internal/curl/curl_test.go | 4 | ||||
-rw-r--r-- | client/go/internal/vespa/deploy.go | 6 | ||||
-rw-r--r-- | client/go/internal/vespa/target.go | 36 |
20 files changed, 89 insertions, 74 deletions
diff --git a/client/go/internal/admin/deploy/curl.go b/client/go/internal/admin/deploy/curl.go index ca044128e93..0ce1305226f 100644 --- a/client/go/internal/admin/deploy/curl.go +++ b/client/go/internal/admin/deploy/curl.go @@ -89,7 +89,7 @@ func runCurl(cmd *curl.Command, stdout io.Writer) error { if err != nil { if ee, ok := err.(*exec.ExitError); ok { if ee.ProcessState.ExitCode() == 7 { - return fmt.Errorf("HTTP request failed. Could not connect to %s", cmd.GetUrlPrefix()) + return fmt.Errorf("HTTP request failed. Could not connect to %s", cmd.URLPrefix()) } } return fmt.Errorf("HTTP request failed with curl %s", err.Error()) diff --git a/client/go/internal/cli/cmd/api_key.go b/client/go/internal/cli/cmd/api_key.go index ef04532314c..133c9db0d3b 100644 --- a/client/go/internal/cli/cmd/api_key.go +++ b/client/go/internal/cli/cmd/api_key.go @@ -58,7 +58,7 @@ Read more in https://cloud.vespa.ai/en/security/guide`, } func doApiKey(cli *CLI, overwriteKey bool, args []string) error { - targetType, err := cli.targetType(true) + targetType, err := cli.targetType(cloudTargetOnly) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/cert.go b/client/go/internal/cli/cmd/cert.go index 9668e78bd1c..6aa99a01902 100644 --- a/client/go/internal/cli/cmd/cert.go +++ b/client/go/internal/cli/cmd/cert.go @@ -103,7 +103,7 @@ $ vespa auth cert add -a my-tenant.my-app.my-instance path/to/application/packag } func doCert(cli *CLI, overwriteCertificate, skipApplicationPackage bool, args []string) error { - targetType, err := cli.targetType(true) + targetType, err := cli.targetType(cloudTargetOnly) if err != nil { return err } @@ -149,7 +149,7 @@ func doCert(cli *CLI, overwriteCertificate, skipApplicationPackage bool, args [] } func doCertAdd(cli *CLI, overwriteCertificate bool, args []string) error { - target, err := cli.target(targetOptions{cloudExclusive: true}) + target, err := cli.target(targetOptions{supportedType: cloudTargetOnly}) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/config_test.go b/client/go/internal/cli/cmd/config_test.go index 64d7d91fef1..b13f8365f5f 100644 --- a/client/go/internal/cli/cmd/config_test.go +++ b/client/go/internal/cli/cmd/config_test.go @@ -272,7 +272,7 @@ func TestConfigTargetResolving(t *testing.T) { } func assertTargetType(t *testing.T, expected string, cli *CLI) { - targetType, err := cli.targetType(false) + targetType, err := cli.targetType(anyTarget) require.Nil(t, err) assert.Equal(t, expected, targetType.name) } diff --git a/client/go/internal/cli/cmd/deploy.go b/client/go/internal/cli/cmd/deploy.go index dd605237b5f..c9331a540eb 100644 --- a/client/go/internal/cli/cmd/deploy.go +++ b/client/go/internal/cli/cmd/deploy.go @@ -117,7 +117,7 @@ func newPrepareCmd(cli *CLI) *cobra.Command { if err != nil { return fmt.Errorf("could not find application package: %w", err) } - target, err := cli.target(targetOptions{}) + target, err := cli.target(targetOptions{supportedType: localTargetOnly}) if err != nil { return err } @@ -153,7 +153,7 @@ func newActivateCmd(cli *CLI) *cobra.Command { if err != nil { return fmt.Errorf("could not read session id: %w", err) } - target, err := cli.target(targetOptions{}) + target, err := cli.target(targetOptions{supportedType: localTargetOnly}) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/destroy.go b/client/go/internal/cli/cmd/destroy.go index f4822330e05..a7beff2e4b4 100644 --- a/client/go/internal/cli/cmd/destroy.go +++ b/client/go/internal/cli/cmd/destroy.go @@ -37,7 +37,7 @@ $ vespa destroy --force`, DisableAutoGenTag: true, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - target, err := cli.target(targetOptions{cloudExclusive: true}) + target, err := cli.target(targetOptions{supportedType: cloudTargetOnly}) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/destroy_test.go b/client/go/internal/cli/cmd/destroy_test.go index bbba593cc5d..c62a54e5925 100644 --- a/client/go/internal/cli/cmd/destroy_test.go +++ b/client/go/internal/cli/cmd/destroy_test.go @@ -57,5 +57,5 @@ func TestDestroy(t *testing.T) { require.Nil(t, cli.Run("config", "set", "target", "local")) require.Nil(t, cli.Run("config", "set", "application", "foo.bar.baz")) require.NotNil(t, cli.Run("destroy", "-z", "prod.aws-us-east-1c")) - assert.Equal(t, "Error: unsupported target local: this command only supports targets cloud and hosted\n", stderr.String()) + assert.Equal(t, "Error: command does not support local target\n", stderr.String()) } diff --git a/client/go/internal/cli/cmd/document.go b/client/go/internal/cli/cmd/document.go index a98e9867d34..6892956880b 100644 --- a/client/go/internal/cli/cmd/document.go +++ b/client/go/internal/cli/cmd/document.go @@ -8,8 +8,6 @@ import ( "bytes" "errors" "fmt" - "io" - "net/http" "os" "strconv" "strings" @@ -17,7 +15,6 @@ import ( "github.com/fatih/color" "github.com/spf13/cobra" - "github.com/vespa-engine/vespa/client/go/internal/curl" "github.com/vespa-engine/vespa/client/go/internal/util" "github.com/vespa-engine/vespa/client/go/internal/vespa" "github.com/vespa-engine/vespa/client/go/internal/vespa/document" @@ -29,54 +26,24 @@ func addDocumentFlags(cli *CLI, cmd *cobra.Command, printCurl *bool, timeoutSecs cli.bindWaitFlag(cmd, 0, waitSecs) } -type serviceWithCurl struct { - curlCmdWriter io.Writer - bodyFile string - service *vespa.Service -} - -func (s *serviceWithCurl) Do(request *http.Request, timeout time.Duration) (*http.Response, error) { - cmd, err := curl.RawArgs(request.URL.String()) - if err != nil { - return nil, err - } - cmd.Method = request.Method - for k, vs := range request.Header { - for _, v := range vs { - cmd.Header(k, v) - } - } - if s.bodyFile != "" { - cmd.WithBodyFile(s.bodyFile) - } - cmd.Certificate = s.service.TLSOptions.CertificateFile - cmd.PrivateKey = s.service.TLSOptions.PrivateKeyFile - out := cmd.String() + "\n" - if _, err := io.WriteString(s.curlCmdWriter, out); err != nil { - return nil, err - } - return s.service.Do(request, timeout) -} - -func documentClient(cli *CLI, timeoutSecs, waitSecs int, printCurl bool) (*document.Client, *serviceWithCurl, error) { +func documentClient(cli *CLI, timeoutSecs, waitSecs int, printCurl bool) (*document.Client, *vespa.Service, error) { docService, err := documentService(cli, waitSecs) if err != nil { return nil, nil, err } - service := &serviceWithCurl{curlCmdWriter: io.Discard, service: docService} if printCurl { - service.curlCmdWriter = cli.Stderr + docService.CurlWriter = vespa.CurlWriter{Writer: cli.Stderr} } client, err := document.NewClient(document.ClientOptions{ Compression: document.CompressionAuto, Timeout: time.Duration(timeoutSecs) * time.Second, BaseURL: docService.BaseURL, NowFunc: time.Now, - }, []util.HTTPClient{service}) + }, []util.HTTPClient{docService}) if err != nil { return nil, nil, err } - return client, service, nil + return client, docService, nil } func sendOperation(op document.Operation, args []string, timeoutSecs, waitSecs int, printCurl bool, cli *CLI) error { @@ -117,10 +84,10 @@ func sendOperation(op document.Operation, args []string, timeoutSecs, waitSecs i doc.Operation = op } if doc.Body != nil { - service.bodyFile = f.Name() + service.CurlWriter.InputFile = f.Name() } result := client.Send(doc) - return printResult(cli, operationResult(false, doc, service.service, result), false) + return printResult(cli, operationResult(false, doc, service, result), false) } func readDocument(id string, timeoutSecs, waitSecs int, printCurl bool, cli *CLI) error { @@ -133,7 +100,7 @@ func readDocument(id string, timeoutSecs, waitSecs int, printCurl bool, cli *CLI return err } result := client.Get(docId) - return printResult(cli, operationResult(true, document.Document{Id: docId}, service.service, result), true) + return printResult(cli, operationResult(true, document.Document{Id: docId}, service, result), true) } func operationResult(read bool, doc document.Document, service *vespa.Service, result document.Result) util.OperationResult { @@ -262,7 +229,7 @@ $ vespa document remove id:mynamespace:music::a-head-full-of-dreams`, } doc := document.Document{Id: id, Operation: document.OperationRemove} result := client.Send(doc) - return printResult(cli, operationResult(false, doc, service.service, result), false) + return printResult(cli, operationResult(false, doc, service, result), false) } else { return sendOperation(document.OperationRemove, args, timeoutSecs, waitSecs, printCurl, cli) } diff --git a/client/go/internal/cli/cmd/document_test.go b/client/go/internal/cli/cmd/document_test.go index 636059acfde..0b8d5a50615 100644 --- a/client/go/internal/cli/cmd/document_test.go +++ b/client/go/internal/cli/cmd/document_test.go @@ -129,7 +129,7 @@ func assertDocumentSend(args []string, expectedOperation string, expectedMethod } } if verbose { - expectedCurl := "curl -X " + expectedMethod + " -H 'Content-Type: application/json; charset=utf-8'" + expectedCurl := "curl -X " + expectedMethod + " -m 66 -H 'Content-Type: application/json; charset=utf-8'" if expectedPayloadFile != "" { expectedCurl += " --data-binary @" + expectedPayloadFile } diff --git a/client/go/internal/cli/cmd/log.go b/client/go/internal/cli/cmd/log.go index e7178b74a56..77ef7f68130 100644 --- a/client/go/internal/cli/cmd/log.go +++ b/client/go/internal/cli/cmd/log.go @@ -34,7 +34,7 @@ $ vespa log --follow`, SilenceUsage: true, Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - target, err := cli.target(targetOptions{logLevel: levelArg, cloudExclusive: true}) + target, err := cli.target(targetOptions{logLevel: levelArg, supportedType: cloudTargetOnly}) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/login.go b/client/go/internal/cli/cmd/login.go index b380e627203..3d63266afbc 100644 --- a/client/go/internal/cli/cmd/login.go +++ b/client/go/internal/cli/cmd/login.go @@ -31,7 +31,7 @@ This command runs a browser-based authentication flow for the Vespa Cloud contro SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - targetType, err := cli.targetType(true) + targetType, err := cli.targetType(cloudTargetOnly) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/logout.go b/client/go/internal/cli/cmd/logout.go index 6cfa6f5b876..80c3d140816 100644 --- a/client/go/internal/cli/cmd/logout.go +++ b/client/go/internal/cli/cmd/logout.go @@ -15,7 +15,7 @@ func newLogoutCmd(cli *CLI) *cobra.Command { DisableAutoGenTag: true, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - targetType, err := cli.targetType(true) + targetType, err := cli.targetType(cloudTargetOnly) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/prod.go b/client/go/internal/cli/cmd/prod.go index 74e4b4c4a1c..d90d89437f9 100644 --- a/client/go/internal/cli/cmd/prod.go +++ b/client/go/internal/cli/cmd/prod.go @@ -53,7 +53,7 @@ https://cloud.vespa.ai/en/reference/deployment`, DisableAutoGenTag: true, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { - target, err := cli.target(targetOptions{noCertificate: true, cloudExclusive: true}) + target, err := cli.target(targetOptions{noCertificate: true, supportedType: cloudTargetOnly}) if err != nil { return err } @@ -135,7 +135,7 @@ https://cloud.vespa.ai/en/reference/vespa-cloud-api#submission-properties Example: `$ mvn package # when adding custom Java components $ vespa prod deploy`, RunE: func(cmd *cobra.Command, args []string) error { - target, err := cli.target(targetOptions{noCertificate: true, cloudExclusive: true}) + target, err := cli.target(targetOptions{noCertificate: true, supportedType: cloudTargetOnly}) if err != nil { return err } diff --git a/client/go/internal/cli/cmd/root.go b/client/go/internal/cli/cmd/root.go index 004bdc038fe..864fe7d1961 100644 --- a/client/go/internal/cli/cmd/root.go +++ b/client/go/internal/cli/cmd/root.go @@ -33,6 +33,10 @@ const ( targetFlag = "target" colorFlag = "color" quietFlag = "quiet" + + anyTarget = iota + localTargetOnly + cloudTargetOnly ) // CLI holds the Vespa CLI command tree, configuration and dependencies. @@ -74,8 +78,8 @@ type targetOptions struct { logLevel string // noCertificate declares that no client certificate should be required when using this target. noCertificate bool - // cloudExclusive specifies whether to only allow Vespa Cloud and Hosted Vespa targets - cloudExclusive bool + // supportedType specifies what type of target to allow. + supportedType int } type targetType struct { @@ -350,7 +354,7 @@ func (c *CLI) waiter(timeout time.Duration) *Waiter { return &Waiter{Timeout: ti // target creates a target according the configuration of this CLI and given opts. func (c *CLI) target(opts targetOptions) (vespa.Target, error) { - targetType, err := c.targetType(opts.cloudExclusive) + targetType, err := c.targetType(opts.supportedType) if err != nil { return nil, err } @@ -375,7 +379,7 @@ func (c *CLI) target(opts targetOptions) (vespa.Target, error) { } // targetType resolves the real target type and its custom URL (if any) -func (c *CLI) targetType(cloud bool) (targetType, error) { +func (c *CLI) targetType(targetTypeRestriction int) (targetType, error) { v, err := c.config.targetOrURL() if err != nil { return targetType{}, err @@ -388,8 +392,10 @@ func (c *CLI) targetType(cloud bool) (targetType, error) { return targetType{}, err } } - if cloud && tt.name != vespa.TargetCloud && tt.name != vespa.TargetHosted { - return targetType{}, fmt.Errorf("unsupported target %s: this command only supports targets %s and %s", tt.name, vespa.TargetCloud, vespa.TargetHosted) + unsupported := (targetTypeRestriction == cloudTargetOnly && tt.name != vespa.TargetCloud && tt.name != vespa.TargetHosted) || + (targetTypeRestriction == localTargetOnly && tt.name != vespa.TargetLocal && tt.name != vespa.TargetCustom) + if unsupported { + return targetType{}, fmt.Errorf("command does not support %s target", tt.name) } return tt, nil } diff --git a/client/go/internal/cli/cmd/visit.go b/client/go/internal/cli/cmd/visit.go index 2ca01764deb..f6e2f64e534 100644 --- a/client/go/internal/cli/cmd/visit.go +++ b/client/go/internal/cli/cmd/visit.go @@ -36,6 +36,7 @@ type visitArgs struct { bucketSpace string bucketSpaces []string waitSecs int + verbose bool cli *CLI } @@ -112,6 +113,9 @@ $ vespa visit --field-set "[id]" # list document IDs if err != nil { return err } + if vArgs.verbose { + service.CurlWriter = vespa.CurlWriter{Writer: cli.Stderr} + } result = probeHandler(service, cli) if result.Success { result = visitClusters(&vArgs, service) @@ -136,6 +140,7 @@ $ vespa visit --field-set "[id]" # list document IDs cmd.Flags().IntVar(&vArgs.sliceId, "slice-id", -1, `The number of the slice this visit invocation should fetch`) cmd.Flags().IntVar(&vArgs.slices, "slices", -1, `Split the document corpus into this number of independent slices`) cmd.Flags().StringSliceVar(&vArgs.bucketSpaces, "bucket-space", []string{"global", "default"}, `The "default" or "global" bucket space`) + cmd.Flags().BoolVarP(&vArgs.verbose, "verbose", "v", false, `Print the equivalent curl command for the visit operation`) cli.bindWaitFlag(cmd, 0, &vArgs.waitSecs) return cmd } diff --git a/client/go/internal/cli/cmd/waiter.go b/client/go/internal/cli/cmd/waiter.go index 0cfb3aa76d5..d818359e61c 100644 --- a/client/go/internal/cli/cmd/waiter.go +++ b/client/go/internal/cli/cmd/waiter.go @@ -31,7 +31,7 @@ func (w *Waiter) DeployService(target vespa.Target) (*vespa.Service, error) { // Service returns the service identified by cluster ID, available on target. func (w *Waiter) Service(target vespa.Target, cluster string) (*vespa.Service, error) { - targetType, err := w.cli.targetType(false) + targetType, err := w.cli.targetType(anyTarget) if err != nil { return nil, err } diff --git a/client/go/internal/curl/curl.go b/client/go/internal/curl/curl.go index 3938938d2f3..e41f48840a2 100644 --- a/client/go/internal/curl/curl.go +++ b/client/go/internal/curl/curl.go @@ -7,9 +7,10 @@ import ( "os/exec" "runtime" "sort" + "strconv" + "time" "github.com/alessio/shellescape" - "github.com/vespa-engine/vespa/client/go/internal/util" ) type header struct { @@ -23,6 +24,7 @@ type Command struct { PrivateKey string CaCertificate string Certificate string + Timeout time.Duration bodyFile string bodyInput io.Reader url *url.URL @@ -30,20 +32,20 @@ type Command struct { rawArgs []string } -func (c *Command) GetUrlPrefix() string { +func (c *Command) URLPrefix() string { return c.url.Scheme + "://" + c.url.Host } func (c *Command) WithBodyFile(fn string) { if c.bodyInput != nil { - util.JustExitMsg("cannot use both WithBodyFile and WithBodyInput") + panic("cannot use both WithBodyFile and WithBodyInput") } c.bodyFile = fn } func (c *Command) WithBodyInput(r io.Reader) { if c.bodyFile != "" { - util.JustExitMsg("cannot use both WithBodyFile and WithBodyInput") + panic("cannot use both WithBodyFile and WithBodyInput") } c.bodyInput = r } @@ -62,6 +64,9 @@ func (c *Command) Args() []string { if c.Method != "" { args = append(args, "-X", c.Method) } + if c.Timeout > 0 { + args = append(args, "-m", strconv.FormatInt(int64(c.Timeout.Seconds()), 10)) + } sort.Slice(c.headers, func(i, j int) bool { return c.headers[i].key < c.headers[j].key }) for _, header := range c.headers { args = append(args, "-H", header.key+": "+header.value) diff --git a/client/go/internal/curl/curl_test.go b/client/go/internal/curl/curl_test.go index 61354c408d2..83bb7e72dbe 100644 --- a/client/go/internal/curl/curl_test.go +++ b/client/go/internal/curl/curl_test.go @@ -3,6 +3,7 @@ package curl import ( "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -13,10 +14,11 @@ func TestPost(t *testing.T) { require.Nil(t, err) c.PrivateKey = "key.pem" c.Certificate = "cert.pem" + c.Timeout = time.Minute c.WithBodyFile("file.json") c.Header("Content-Type", "application/json") - assert.Equal(t, "curl --key key.pem --cert cert.pem -X POST -H 'Content-Type: application/json' --data-binary @file.json https://example.com", c.String()) + assert.Equal(t, "curl --key key.pem --cert cert.pem -X POST -m 60 -H 'Content-Type: application/json' --data-binary @file.json https://example.com", c.String()) } func TestGet(t *testing.T) { diff --git a/client/go/internal/vespa/deploy.go b/client/go/internal/vespa/deploy.go index 4684e313291..7d90930d5f9 100644 --- a/client/go/internal/vespa/deploy.go +++ b/client/go/internal/vespa/deploy.go @@ -242,9 +242,6 @@ func fetchFilesFromConfigServer(deployment DeploymentOptions, contentURL *url.UR // Prepare deployment and return the session ID func Prepare(deployment DeploymentOptions) (PrepareResult, error) { - if deployment.Target.IsCloud() { - return PrepareResult{}, fmt.Errorf("prepare is not supported with %s target", deployment.Target.Type()) - } sessionURL, err := deployment.url("/application/v2/tenant/default/session") if err != nil { return PrepareResult{}, err @@ -290,9 +287,6 @@ func Prepare(deployment DeploymentOptions) (PrepareResult, error) { // Activate deployment with sessionID from a past prepare func Activate(sessionID int64, deployment DeploymentOptions) error { - if deployment.Target.IsCloud() { - return fmt.Errorf("activate is not supported with %s target", deployment.Target.Type()) - } u, err := deployment.url(fmt.Sprintf("/application/v2/tenant/default/session/%d/active", sessionID)) if err != nil { return err diff --git a/client/go/internal/vespa/target.go b/client/go/internal/vespa/target.go index f3a94f762ff..3a76eac0292 100644 --- a/client/go/internal/vespa/target.go +++ b/client/go/internal/vespa/target.go @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/vespa-engine/vespa/client/go/internal/curl" "github.com/vespa-engine/vespa/client/go/internal/util" "github.com/vespa-engine/vespa/client/go/internal/version" ) @@ -43,11 +44,43 @@ type Authenticator interface { Authenticate(request *http.Request) error } +// CurlWriter configures printing of Curl-equivalent commands for HTTP requests passing through a Service. +type CurlWriter struct { + Writer io.Writer + InputFile string +} + +func (c *CurlWriter) print(request *http.Request, tlsOptions TLSOptions, timeout time.Duration) error { + if c.Writer == nil { + return nil + } + cmd, err := curl.RawArgs(request.URL.String()) + if err != nil { + return err + } + cmd.Method = request.Method + for k, vs := range request.Header { + for _, v := range vs { + cmd.Header(k, v) + } + } + cmd.CaCertificate = tlsOptions.CACertificateFile + cmd.Certificate = tlsOptions.CertificateFile + cmd.PrivateKey = tlsOptions.PrivateKeyFile + cmd.Timeout = timeout + if c.InputFile != "" { + cmd.WithBodyFile(c.InputFile) + } + _, err = fmt.Fprintln(c.Writer, cmd.String()) + return err +} + // Service represents a Vespa service. type Service struct { BaseURL string Name string TLSOptions TLSOptions + CurlWriter CurlWriter deployAPI bool auth Authenticator @@ -117,6 +150,9 @@ func (s *Service) Do(request *http.Request, timeout time.Duration) (*http.Respon return nil, fmt.Errorf("%w: %s", errAuth, err) } } + if err := s.CurlWriter.print(request, s.TLSOptions, timeout); err != nil { + return nil, err + } return s.httpClient.Do(request, timeout) } |