summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-09-22 09:03:48 +0200
committerMartin Polden <mpolden@mpolden.no>2021-09-22 10:40:12 +0200
commitb6d3d1814961d95c84d4dac12e875b6fa3bdc3d6 (patch)
tree3fad3696cdaa3f65975fb7a931d76a84eab7c4a2 /client
parent302ddbdeee930c9e951aa5d0b2004c731b621e3d (diff)
Extract curl package
Diffstat (limited to 'client')
-rw-r--r--client/go/cmd/curl.go95
-rw-r--r--client/go/cmd/curl_test.go37
-rw-r--r--client/go/curl/curl.go104
-rw-r--r--client/go/curl/curl_test.go45
4 files changed, 168 insertions, 113 deletions
diff --git a/client/go/cmd/curl.go b/client/go/cmd/curl.go
index f6b40e10f35..bd9fad1b47e 100644
--- a/client/go/cmd/curl.go
+++ b/client/go/cmd/curl.go
@@ -1,22 +1,19 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package cmd
import (
- "fmt"
"log"
"os"
- "os/exec"
"strings"
- "github.com/kballard/go-shellquote"
"github.com/spf13/cobra"
+ "github.com/vespa-engine/vespa/client/go/curl"
)
var curlDryRun bool
-var curlPath string
func init() {
rootCmd.AddCommand(curlCmd)
- curlCmd.Flags().StringVarP(&curlPath, "path", "p", "", "The path to curl. If this is unset, curl from PATH is used")
curlCmd.Flags().BoolVarP(&curlDryRun, "dry-run", "n", false, "Print the curl command that would be executed")
}
@@ -50,16 +47,20 @@ $ vespa curl -t local -- -v /search/?yql=query
return
}
service := getService("query", 0)
- c := &curl{privateKeyPath: privateKeyFile, certificatePath: certificateFile}
+ url := joinURL(service.BaseURL, args[len(args)-1])
+ rawArgs := args[:len(args)-1]
+ c, err := curl.RawArgs(url, rawArgs...)
+ if err != nil {
+ fatalErr(err)
+ return
+ }
+ c.PrivateKey = privateKeyFile
+ c.Certificate = certificateFile
+
if curlDryRun {
- cmd, err := c.command(service.BaseURL, args...)
- if err != nil {
- fatalErr(err, "Failed to create curl command")
- return
- }
- log.Print(shellquote.Join(cmd.Args...))
+ log.Print(c.String())
} else {
- if err := c.run(service.BaseURL, args...); err != nil {
+ if err := c.Run(os.Stdout, os.Stderr); err != nil {
fatalErr(err, "Failed to run curl")
return
}
@@ -67,72 +68,8 @@ $ vespa curl -t local -- -v /search/?yql=query
},
}
-type curl struct {
- path string
- certificatePath string
- privateKeyPath string
-}
-
-func (c *curl) run(baseURL string, args ...string) error {
- cmd, err := c.command(baseURL, args...)
- if err != nil {
- return err
- }
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if err := cmd.Start(); err != nil {
- return err
- }
- return cmd.Wait()
-}
-
-func (c *curl) command(baseURL string, args ...string) (*exec.Cmd, error) {
- if len(args) == 0 {
- return nil, fmt.Errorf("need at least one argument")
- }
-
- if c.path == "" {
- resolvedPath, err := resolveCurlPath()
- if err != nil {
- return nil, err
- }
- c.path = resolvedPath
- }
-
- path := args[len(args)-1]
- args = args[:len(args)-1]
- if !hasOption("--key", args) && c.privateKeyPath != "" {
- args = append(args, "--key", c.privateKeyPath)
- }
- if !hasOption("--cert", args) && c.certificatePath != "" {
- args = append(args, "--cert", c.certificatePath)
- }
-
+func joinURL(baseURL, path string) string {
baseURL = strings.TrimSuffix(baseURL, "/")
path = strings.TrimPrefix(path, "/")
- args = append(args, baseURL+"/"+path)
-
- return exec.Command(c.path, args...), nil
-}
-
-func hasOption(option string, args []string) bool {
- for _, arg := range args {
- if arg == option {
- return true
- }
- }
- return false
-}
-
-func resolveCurlPath() (string, error) {
- var curlPath string
- var err error
- curlPath, err = exec.LookPath("curl")
- if err != nil {
- curlPath, err = exec.LookPath("curl.exe")
- if err != nil {
- return "", err
- }
- }
- return curlPath, nil
+ return baseURL + "/" + path
}
diff --git a/client/go/cmd/curl_test.go b/client/go/cmd/curl_test.go
index c3163e731ce..340eacd0bd3 100644
--- a/client/go/cmd/curl_test.go
+++ b/client/go/cmd/curl_test.go
@@ -1,9 +1,9 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package cmd
import (
"fmt"
"path/filepath"
- "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -13,41 +13,10 @@ func TestCurl(t *testing.T) {
homeDir := t.TempDir()
httpClient := &mockHttpClient{}
convergeServices(httpClient)
- out := execute(command{homeDir: homeDir, args: []string{"curl", "-n", "-p", "/usr/bin/curl", "-a", "t1.a1.i1", "--", "-v", "--data-urlencode", "arg=with space", "/search"}}, t, httpClient)
+ out, _ := execute(command{homeDir: homeDir, args: []string{"curl", "-n", "-a", "t1.a1.i1", "--", "-v", "--data-urlencode", "arg=with space", "/search"}}, t, httpClient)
- expected := fmt.Sprintf("/usr/bin/curl -v --data-urlencode 'arg=with space' --key %s --cert %s https://127.0.0.1:8080/search\n",
+ expected := fmt.Sprintf("curl --key %s --cert %s -v --data-urlencode 'arg=with space' https://127.0.0.1:8080/search\n",
filepath.Join(homeDir, ".vespa", "t1.a1.i1", "data-plane-private-key.pem"),
filepath.Join(homeDir, ".vespa", "t1.a1.i1", "data-plane-public-cert.pem"))
assert.Equal(t, expected, out)
}
-
-func TestCurlCommand(t *testing.T) {
- c := &curl{path: "/usr/bin/curl", privateKeyPath: "/tmp/priv-key", certificatePath: "/tmp/cert-key"}
- assertCurl(t, c, "/usr/bin/curl -v --key /tmp/priv-key --cert /tmp/cert-key https://example.com/", "-v", "/")
-
- c = &curl{path: "/usr/bin/curl", privateKeyPath: "/tmp/priv-key", certificatePath: "/tmp/cert-key"}
- assertCurl(t, c, "/usr/bin/curl -v --cert my-cert --key my-key https://example.com/", "-v", "--cert", "my-cert", "--key", "my-key", "/")
-
- c = &curl{path: "/usr/bin/curl2"}
- assertCurl(t, c, "/usr/bin/curl2 -v https://example.com/foo", "-v", "/foo")
-
- c = &curl{path: "/usr/bin/curl"}
- assertCurl(t, c, "/usr/bin/curl -v https://example.com/foo/bar", "-v", "/foo/bar")
-
- c = &curl{path: "/usr/bin/curl"}
- assertCurl(t, c, "/usr/bin/curl -v https://example.com/foo/bar", "-v", "foo/bar")
-
- c = &curl{path: "/usr/bin/curl"}
- assertCurlURL(t, c, "/usr/bin/curl -v https://example.com/foo/bar", "https://example.com/", "-v", "foo/bar")
-}
-
-func assertCurl(t *testing.T, c *curl, expectedOutput string, args ...string) {
- assertCurlURL(t, c, expectedOutput, "https://example.com", args...)
-}
-
-func assertCurlURL(t *testing.T, c *curl, expectedOutput string, url string, args ...string) {
- cmd, err := c.command("https://example.com", args...)
- assert.Nil(t, err)
-
- assert.Equal(t, expectedOutput, strings.Join(cmd.Args, " "))
-}
diff --git a/client/go/curl/curl.go b/client/go/curl/curl.go
new file mode 100644
index 00000000000..44c3a0ad2a9
--- /dev/null
+++ b/client/go/curl/curl.go
@@ -0,0 +1,104 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package curl
+
+import (
+ "io"
+ "net/url"
+ "os/exec"
+ "runtime"
+
+ "github.com/kballard/go-shellquote"
+)
+
+type header struct {
+ key string
+ value string
+}
+
+type Command struct {
+ Path string
+ Method string
+ PrivateKey string
+ Certificate string
+ BodyFile string
+ url *url.URL
+ headers []header
+ rawArgs []string
+}
+
+func (c *Command) Args() []string {
+ var args []string
+ if c.PrivateKey != "" {
+ args = append(args, "--key", c.PrivateKey)
+ }
+ if c.Certificate != "" {
+ args = append(args, "--cert", c.Certificate)
+ }
+ if c.Method != "" {
+ args = append(args, "-X", c.Method)
+ }
+ for _, header := range c.headers {
+ args = append(args, "-H", header.key+": "+header.value)
+ }
+ if c.BodyFile != "" {
+ args = append(args, "--data-binary", "@"+c.BodyFile)
+ }
+ args = append(args, c.rawArgs...)
+ args = append(args, c.url.String())
+ return args
+}
+
+func (c *Command) String() string {
+ args := []string{c.Path}
+ args = append(args, c.Args()...)
+ return shellquote.Join(args...)
+}
+
+func (c *Command) Header(key, value string) {
+ c.headers = append(c.headers, header{key: key, value: value})
+}
+
+func (c *Command) Param(key, value string) {
+ query := c.url.Query()
+ query.Set(key, value)
+ c.url.RawQuery = query.Encode()
+}
+
+func (c *Command) Run(stdout, stderr io.Writer) error {
+ cmd := exec.Command(c.Path, c.Args()...)
+ cmd.Stdout = stdout
+ cmd.Stderr = stderr
+ if err := cmd.Start(); err != nil {
+ return err
+ }
+ return cmd.Wait()
+}
+
+func Post(url string) (*Command, error) { return curl("POST", url) }
+
+func Get(url string) (*Command, error) { return curl("", url) }
+
+func RawArgs(url string, args ...string) (*Command, error) {
+ c, err := curl("", url)
+ if err != nil {
+ return nil, err
+ }
+ c.rawArgs = args
+ return c, nil
+}
+
+func curl(method, rawurl string) (*Command, error) {
+ path := "curl"
+ if runtime.GOOS == "windows" {
+ path = "curl.exe"
+ }
+ realURL, err := url.Parse(rawurl)
+ if err != nil {
+ return nil, err
+ }
+ return &Command{
+ Path: path,
+ Method: method,
+ url: realURL,
+ }, nil
+}
diff --git a/client/go/curl/curl_test.go b/client/go/curl/curl_test.go
new file mode 100644
index 00000000000..90bf274f7a2
--- /dev/null
+++ b/client/go/curl/curl_test.go
@@ -0,0 +1,45 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package curl
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestPost(t *testing.T) {
+ c, err := Post("https://example.com")
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.PrivateKey = "key.pem"
+ c.Certificate = "cert.pem"
+ c.BodyFile = "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())
+}
+
+func TestGet(t *testing.T) {
+ c, err := Get("https://example.com")
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.PrivateKey = "key.pem"
+ c.Certificate = "cert.pem"
+ c.Param("yql", "select * from sources * where title contains 'foo';")
+ c.Param("hits", "5")
+
+ assert.Equal(t, `curl --key key.pem --cert cert.pem https://example.com\?hits=5\&yql=select+%2A+from+sources+%2A+where+title+contains+%27foo%27%3B`, c.String())
+}
+
+func TestRawArgs(t *testing.T) {
+ c, err := RawArgs("https://example.com/search", "-v", "-m", "10", "-H", "foo: bar")
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.PrivateKey = "key.pem"
+ c.Certificate = "cert.pem"
+
+ assert.Equal(t, `curl --key key.pem --cert cert.pem -v -m 10 -H 'foo: bar' https://example.com/search`, c.String())
+}