summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-06-30 20:38:27 +0200
committerGitHub <noreply@github.com>2022-06-30 20:38:27 +0200
commitb68a837f1079d3ccbfd739aee39796ce73edac24 (patch)
treea25a539a0362cfcc7877b14174d795c3c04317f2 /client
parent239a8e44dac7b3078f47b58dd0d358640f8cb089 (diff)
parent270b58aadb6af7fdd9dcadd09ee517cdbf1f3e20 (diff)
Merge pull request #23284 from vespa-engine/mpolden/cli-cluster
Support specifying cluster name in CLI
Diffstat (limited to 'client')
-rw-r--r--client/go/cmd/api_key.go5
-rw-r--r--client/go/cmd/api_key_test.go3
-rw-r--r--client/go/cmd/cert.go9
-rw-r--r--client/go/cmd/cert_test.go6
-rw-r--r--client/go/cmd/config.go16
-rw-r--r--client/go/cmd/config_test.go6
-rw-r--r--client/go/cmd/curl.go2
-rw-r--r--client/go/cmd/curl_test.go1
-rw-r--r--client/go/cmd/deploy.go2
-rw-r--r--client/go/cmd/document.go2
-rw-r--r--client/go/cmd/query.go2
-rw-r--r--client/go/cmd/root.go13
-rw-r--r--client/go/cmd/status.go2
-rw-r--r--client/go/vespa/target_cloud.go30
14 files changed, 53 insertions, 46 deletions
diff --git a/client/go/cmd/api_key.go b/client/go/cmd/api_key.go
index 00630be7603..a7d405963b0 100644
--- a/client/go/cmd/api_key.go
+++ b/client/go/cmd/api_key.go
@@ -14,7 +14,7 @@ import (
"github.com/vespa-engine/vespa/client/go/vespa"
)
-func newAPIKeyCmd(cli *CLI, deprecated bool) *cobra.Command {
+func newAPIKeyCmd(cli *CLI) *cobra.Command {
var overwriteKey bool
cmd := &cobra.Command{
Use: "api-key",
@@ -46,9 +46,6 @@ always be used. It's not possible to specify a tenant-specific key.`,
return doApiKey(cli, overwriteKey, args)
},
}
- if deprecated {
- cmd.Deprecated = "use 'vespa auth api-key' instead"
- }
cmd.Flags().BoolVarP(&overwriteKey, "force", "f", false, "Force overwrite of existing API key")
cmd.MarkPersistentFlagRequired(applicationFlag)
return cmd
diff --git a/client/go/cmd/api_key_test.go b/client/go/cmd/api_key_test.go
index 3e3a7fa0a31..9c14033f85b 100644
--- a/client/go/cmd/api_key_test.go
+++ b/client/go/cmd/api_key_test.go
@@ -13,9 +13,6 @@ func TestAPIKey(t *testing.T) {
t.Run("auth api-key", func(t *testing.T) {
testAPIKey(t, []string{"auth", "api-key"})
})
- t.Run("api-key (deprecated)", func(t *testing.T) {
- testAPIKey(t, []string{"api-key"})
- })
}
func testAPIKey(t *testing.T, subcommand []string) {
diff --git a/client/go/cmd/cert.go b/client/go/cmd/cert.go
index 581c76b8721..ac4d5085782 100644
--- a/client/go/cmd/cert.go
+++ b/client/go/cmd/cert.go
@@ -16,7 +16,7 @@ import (
"github.com/vespa-engine/vespa/client/go/vespa"
)
-func newCertCmd(cli *CLI, deprecated bool) *cobra.Command {
+func newCertCmd(cli *CLI) *cobra.Command {
var (
noApplicationPackage bool
overwriteCertificate bool
@@ -57,12 +57,7 @@ $ vespa auth cert -a my-tenant.my-app.my-instance path/to/application/package`,
},
}
cmd.Flags().BoolVarP(&overwriteCertificate, "force", "f", false, "Force overwrite of existing certificate and private key")
- if deprecated {
- // TODO: Remove this after 2022-06-01
- cmd.Deprecated = "use 'vespa auth cert' instead"
- } else {
- cmd.Flags().BoolVarP(&noApplicationPackage, "no-add", "N", false, "Do not add certificate to the application package")
- }
+ cmd.Flags().BoolVarP(&noApplicationPackage, "no-add", "N", false, "Do not add certificate to the application package")
cmd.MarkPersistentFlagRequired(applicationFlag)
return cmd
}
diff --git a/client/go/cmd/cert_test.go b/client/go/cmd/cert_test.go
index ee0c21adaf5..fe983e0ad5a 100644
--- a/client/go/cmd/cert_test.go
+++ b/client/go/cmd/cert_test.go
@@ -20,9 +20,6 @@ func TestCert(t *testing.T) {
t.Run("auth cert", func(t *testing.T) {
testCert(t, []string{"auth", "cert"})
})
- t.Run("cert (deprecated)", func(t *testing.T) {
- testCert(t, []string{"cert"})
- })
}
func testCert(t *testing.T, subcommand []string) {
@@ -53,9 +50,6 @@ func TestCertCompressedPackage(t *testing.T) {
t.Run("auth cert", func(t *testing.T) {
testCertCompressedPackage(t, []string{"auth", "cert"})
})
- t.Run("cert (deprecated)", func(t *testing.T) {
- testCertCompressedPackage(t, []string{"cert"})
- })
}
func testCertCompressedPackage(t *testing.T, subcommand []string) {
diff --git a/client/go/cmd/config.go b/client/go/cmd/config.go
index b8a7cb9c24c..8f81f8e359f 100644
--- a/client/go/cmd/config.go
+++ b/client/go/cmd/config.go
@@ -62,6 +62,14 @@ and "hosted" targets. See https://cloud.vespa.ai/en/tenant-apps-instances for
more details. This has no default value. Examples: tenant1.app1,
tenant1.app1.instance1
+cluster
+
+Specifies the container cluster to manage. If left empty (default) and the
+application has only one container cluster, that cluster is chosen
+automatically. When an application has multiple cluster this must be set a
+valid cluster name, as specified in services.xml. See
+https://docs.vespa.ai/en/reference/services-container.html for more details.
+
color
Controls how Vespa CLI uses colors. Setting this to "auto" (default) enables
@@ -353,6 +361,11 @@ func (c *Config) application() (vespa.ApplicationID, error) {
return application, nil
}
+func (c *Config) cluster() string {
+ cluster, _ := c.get(clusterFlag)
+ return cluster
+}
+
func (c *Config) deploymentIn(system vespa.System) (vespa.Deployment, error) {
zone := system.DefaultZone
zoneName, ok := c.get(zoneFlag)
@@ -558,6 +571,9 @@ func (c *Config) set(option, value string) error {
case instanceFlag:
c.config.Set(option, value)
return nil
+ case clusterFlag:
+ c.config.Set(clusterFlag, value)
+ return nil
case waitFlag:
if n, err := strconv.Atoi(value); err != nil || n < 0 {
return fmt.Errorf("%s option must be an integer >= 0, got %q", option, value)
diff --git a/client/go/cmd/config_test.go b/client/go/cmd/config_test.go
index 86c7e2695fa..7d701931a04 100644
--- a/client/go/cmd/config_test.go
+++ b/client/go/cmd/config_test.go
@@ -35,6 +35,11 @@ func TestConfig(t *testing.T) {
assertConfigCommand(t, configHome, "", "config", "set", "application", "t1.a1")
assertConfigCommand(t, configHome, "application = t1.a1.default\n", "config", "get", "application")
+ // cluster
+ assertConfigCommand(t, configHome, "cluster = <unset>\n", "config", "get", "cluster")
+ assertConfigCommand(t, configHome, "", "config", "set", "cluster", "feed")
+ assertConfigCommand(t, configHome, "cluster = feed\n", "config", "get", "cluster")
+
// instance
assertConfigCommand(t, configHome, "instance = <unset>\n", "config", "get", "instance")
assertConfigCommand(t, configHome, "", "config", "set", "instance", "i2")
@@ -99,6 +104,7 @@ func TestLocalConfig(t *testing.T) {
// get merges settings from local and global config
assertConfigCommand(t, configHome, "", "config", "set", "--local", "application", "t1.a1")
assertConfigCommand(t, configHome, `application = t1.a1.default
+cluster = <unset>
color = auto
instance = foo
quiet = false
diff --git a/client/go/cmd/curl.go b/client/go/cmd/curl.go
index 41e37f5319b..4b2eb9ba987 100644
--- a/client/go/cmd/curl.go
+++ b/client/go/cmd/curl.go
@@ -38,7 +38,7 @@ $ vespa curl -- -v --data-urlencode "yql=select * from music where album contain
if err != nil {
return err
}
- service, err := target.Service(curlService, 0, 0, "")
+ service, err := target.Service(curlService, 0, 0, cli.config.cluster())
if err != nil {
return err
}
diff --git a/client/go/cmd/curl_test.go b/client/go/cmd/curl_test.go
index 520cf41e308..3eca0726bb4 100644
--- a/client/go/cmd/curl_test.go
+++ b/client/go/cmd/curl_test.go
@@ -14,6 +14,7 @@ func TestCurl(t *testing.T) {
cli.Environment["VESPA_CLI_ENDPOINTS"] = "{\"endpoints\":[{\"cluster\":\"container\",\"url\":\"http://127.0.0.1:8080\"}]}"
assert.Nil(t, cli.Run("config", "set", "application", "t1.a1.i1"))
assert.Nil(t, cli.Run("config", "set", "target", "cloud"))
+ assert.Nil(t, cli.Run("config", "set", "cluster", "container"))
assert.Nil(t, cli.Run("auth", "api-key"))
assert.Nil(t, cli.Run("auth", "cert", "--no-add"))
diff --git a/client/go/cmd/deploy.go b/client/go/cmd/deploy.go
index 930e25dddc7..e72667e49b6 100644
--- a/client/go/cmd/deploy.go
+++ b/client/go/cmd/deploy.go
@@ -178,7 +178,7 @@ func waitForQueryService(cli *CLI, target vespa.Target, sessionOrRunID int64) er
}
if timeout > 0 {
log.Println()
- _, err := cli.service(target, vespa.QueryService, sessionOrRunID, "")
+ _, err := cli.service(target, vespa.QueryService, sessionOrRunID, cli.config.cluster())
return err
}
return nil
diff --git a/client/go/cmd/document.go b/client/go/cmd/document.go
index 32648393492..b2f71121d1a 100644
--- a/client/go/cmd/document.go
+++ b/client/go/cmd/document.go
@@ -178,7 +178,7 @@ func documentService(cli *CLI) (*vespa.Service, error) {
if err != nil {
return nil, err
}
- return cli.service(target, vespa.DocumentService, 0, "")
+ return cli.service(target, vespa.DocumentService, 0, cli.config.cluster())
}
func operationOptions(stderr io.Writer, printCurl bool, timeoutSecs int) vespa.OperationOptions {
diff --git a/client/go/cmd/query.go b/client/go/cmd/query.go
index 82ff5185cbd..d147e986cec 100644
--- a/client/go/cmd/query.go
+++ b/client/go/cmd/query.go
@@ -62,7 +62,7 @@ func query(cli *CLI, arguments []string, timeoutSecs int, curl bool) error {
if err != nil {
return err
}
- service, err := cli.service(target, vespa.QueryService, 0, "")
+ service, err := cli.service(target, vespa.QueryService, 0, cli.config.cluster())
if err != nil {
return err
}
diff --git a/client/go/cmd/root.go b/client/go/cmd/root.go
index 0557248cedf..e2f03cbc7ce 100644
--- a/client/go/cmd/root.go
+++ b/client/go/cmd/root.go
@@ -28,6 +28,7 @@ import (
const (
applicationFlag = "application"
instanceFlag = "instance"
+ clusterFlag = "cluster"
zoneFlag = "zone"
targetFlag = "target"
waitFlag = "wait"
@@ -178,14 +179,16 @@ func (c *CLI) configureFlags() map[string]*pflag.Flag {
target string
application string
instance string
+ cluster string
zone string
waitSecs int
color string
quiet bool
)
c.cmd.PersistentFlags().StringVarP(&target, targetFlag, "t", "local", `The target platform to use. Must be "local", "cloud", "hosted" or an URL`)
- c.cmd.PersistentFlags().StringVarP(&application, applicationFlag, "a", "", "The application to manage")
- c.cmd.PersistentFlags().StringVarP(&instance, instanceFlag, "i", "", "The instance of the application to manage")
+ c.cmd.PersistentFlags().StringVarP(&application, applicationFlag, "a", "", "The application to use")
+ c.cmd.PersistentFlags().StringVarP(&instance, instanceFlag, "i", "", "The instance of the application to use")
+ c.cmd.PersistentFlags().StringVarP(&cluster, clusterFlag, "C", "", "The container cluster to use. This is only required for applications with multiple clusters")
c.cmd.PersistentFlags().StringVarP(&zone, zoneFlag, "z", "", "The zone to use. This defaults to a dev zone")
c.cmd.PersistentFlags().IntVarP(&waitSecs, waitFlag, "w", 0, "Number of seconds to wait for a service to become ready")
c.cmd.PersistentFlags().StringVarP(&color, colorFlag, "c", "auto", `Whether to use colors in output. Must be "auto", "never", or "always"`)
@@ -213,19 +216,17 @@ func (c *CLI) configureSpinner() {
func (c *CLI) configureCommands() {
rootCmd := c.cmd
authCmd := newAuthCmd()
- certCmd := newCertCmd(c, false)
+ certCmd := newCertCmd(c)
configCmd := newConfigCmd()
documentCmd := newDocumentCmd(c)
prodCmd := newProdCmd()
statusCmd := newStatusCmd(c)
certCmd.AddCommand(newCertAddCmd(c)) // auth cert add
authCmd.AddCommand(certCmd) // auth cert
- authCmd.AddCommand(newAPIKeyCmd(c, false)) // auth api-key
+ authCmd.AddCommand(newAPIKeyCmd(c)) // auth api-key
authCmd.AddCommand(newLoginCmd(c)) // auth login
authCmd.AddCommand(newLogoutCmd(c)) // auth logout
rootCmd.AddCommand(authCmd) // auth
- rootCmd.AddCommand(newCertCmd(c, true)) // cert TODO: Remove this after 2022-06-01
- rootCmd.AddCommand(newAPIKeyCmd(c, true)) // api-key TODO: Remove this after 2022-06-01
rootCmd.AddCommand(newCloneCmd(c)) // clone
configCmd.AddCommand(newConfigGetCmd(c)) // config get
configCmd.AddCommand(newConfigSetCmd(c)) // config set
diff --git a/client/go/cmd/status.go b/client/go/cmd/status.go
index 65da8f8f1c0..c44bbddb98a 100644
--- a/client/go/cmd/status.go
+++ b/client/go/cmd/status.go
@@ -81,7 +81,7 @@ func printServiceStatus(cli *CLI, name string) error {
if timeout > 0 {
log.Printf("Waiting up to %s for service to become ready ...", color.CyanString(timeout.String()))
}
- s, err := t.Service(name, timeout, 0, "")
+ s, err := t.Service(name, timeout, 0, cli.config.cluster())
if err != nil {
return err
}
diff --git a/client/go/vespa/target_cloud.go b/client/go/vespa/target_cloud.go
index 696d5109015..1076724a252 100644
--- a/client/go/vespa/target_cloud.go
+++ b/client/go/vespa/target_cloud.go
@@ -9,6 +9,7 @@ import (
"net/http"
"sort"
"strconv"
+ "strings"
"time"
"github.com/vespa-engine/vespa/client/go/auth/auth0"
@@ -82,28 +83,27 @@ func CloudTarget(httpClient util.HTTPClient, apiOptions APIOptions, deploymentOp
}, nil
}
-func (t *cloudTarget) resolveEndpoint(cluster string) (string, error) {
+func (t *cloudTarget) findClusterURL(cluster string) (string, error) {
+ clusters := make([]string, 0, len(t.deploymentOptions.ClusterURLs))
+ for c := range t.deploymentOptions.ClusterURLs {
+ clusters = append(clusters, c)
+ }
if cluster == "" {
- for _, u := range t.deploymentOptions.ClusterURLs {
+ for _, url := range t.deploymentOptions.ClusterURLs {
if len(t.deploymentOptions.ClusterURLs) == 1 {
- return u, nil
+ return url, nil
} else {
- return "", fmt.Errorf("multiple clusters, none chosen: %v", t.deploymentOptions.ClusterURLs)
+ return "", fmt.Errorf("no cluster specified: found multiple clusters '%s'", strings.Join(clusters, "', '"))
}
}
} else {
- u := t.deploymentOptions.ClusterURLs[cluster]
- if u == "" {
- clusters := make([]string, len(t.deploymentOptions.ClusterURLs))
- for c := range t.deploymentOptions.ClusterURLs {
- clusters = append(clusters, c)
- }
- return "", fmt.Errorf("unknown cluster '%s': must be one of %v", cluster, clusters)
+ url, ok := t.deploymentOptions.ClusterURLs[cluster]
+ if !ok {
+ return "", fmt.Errorf("invalid cluster '%s': must be one of '%s'", cluster, strings.Join(clusters, "', '"))
}
- return u, nil
+ return url, nil
}
-
- return "", fmt.Errorf("no endpoints")
+ return "", fmt.Errorf("no endpoints found")
}
func (t *cloudTarget) Type() string {
@@ -142,7 +142,7 @@ func (t *cloudTarget) Service(name string, timeout time.Duration, runID int64, c
return nil, err
}
}
- url, err := t.resolveEndpoint(cluster)
+ url, err := t.findClusterURL(cluster)
if err != nil {
return nil, err
}