summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2022-03-21 09:07:58 +0100
committerGitHub <noreply@github.com>2022-03-21 09:07:58 +0100
commitbff04b8c35e618e4fdcd43743c7865bf5a046344 (patch)
tree20511d859162117396dd7055020786d78790519a
parent6dc4b8fefbb9d1cc09630c353bedfa339d215128 (diff)
parent11573eedb1bf0674a9aac4c09652ad6ea76e0bac (diff)
Merge pull request #21749 from vespa-engine/mpolden/cli-instance
Add instance option
-rw-r--r--client/go/cmd/config.go28
-rw-r--r--client/go/cmd/config_test.go8
-rw-r--r--client/go/cmd/root.go6
-rw-r--r--client/go/vespa/deploy.go8
-rw-r--r--client/go/vespa/deploy_test.go4
5 files changed, 45 insertions, 9 deletions
diff --git a/client/go/cmd/config.go b/client/go/cmd/config.go
index 27d84f0bcda..18af9c89771 100644
--- a/client/go/cmd/config.go
+++ b/client/go/cmd/config.go
@@ -50,9 +50,19 @@ overridden by setting the VESPA_CLI_HOME environment variable.`,
func newConfigSetCmd(cli *CLI) *cobra.Command {
return &cobra.Command{
- Use: "set option-name value",
- Short: "Set a configuration option.",
- Example: "$ vespa config set target cloud",
+ Use: "set option-name value",
+ Short: "Set a configuration option.",
+ Example: `# Set the target to Vespa Cloud
+$ vespa config set target cloud
+
+# Set application, without a specific instance. The instance will be named "default"
+$ vespa config set application my-tenant.my-application
+
+# Set application with a specific instance
+$ vespa config set application my-tenant.my-application.my-instance
+
+# Set the instance explicitly. This will take precedence over an instance specified as part of the application option.
+$ vespa config set instance other-instance`,
DisableAutoGenTag: true,
SilenceUsage: true,
Args: cobra.ExactArgs(2),
@@ -176,7 +186,11 @@ func (c *Config) application() (vespa.ApplicationID, error) {
}
application, err := vespa.ApplicationFromString(app)
if err != nil {
- return vespa.ApplicationID{}, errHint(err, "application format is <tenant>.<app>.<instance>")
+ return vespa.ApplicationID{}, errHint(err, "application format is <tenant>.<app>[.<instance>]")
+ }
+ instance, ok := c.get(instanceFlag)
+ if ok {
+ application.Instance = instance
}
return application, nil
}
@@ -346,9 +360,13 @@ func (c *Config) set(option, value string) error {
return nil
}
case applicationFlag:
- if _, err := vespa.ApplicationFromString(value); err != nil {
+ app, err := vespa.ApplicationFromString(value)
+ if err != nil {
return err
}
+ viper.Set(option, app.String())
+ return nil
+ case instanceFlag:
viper.Set(option, value)
return nil
case waitFlag:
diff --git a/client/go/cmd/config_test.go b/client/go/cmd/config_test.go
index 5f0d745990e..9f695429e99 100644
--- a/client/go/cmd/config_test.go
+++ b/client/go/cmd/config_test.go
@@ -31,7 +31,7 @@ func TestConfig(t *testing.T) {
assertConfigCommand(t, "", "config", "set", "application", "t1.a1.i1")
assertConfigCommand(t, "application = t1.a1.i1\n", "config", "get", "application")
- assertConfigCommand(t, "api-key-file = /tmp/private.key\napplication = t1.a1.i1\ncolor = auto\nquiet = false\ntarget = https://127.0.0.1\nwait = 0\n", "config", "get")
+ assertConfigCommand(t, "api-key-file = /tmp/private.key\napplication = t1.a1.i1\ncolor = auto\ninstance = <unset>\nquiet = false\ntarget = https://127.0.0.1\nwait = 0\n", "config", "get")
assertConfigCommand(t, "", "config", "set", "wait", "60")
assertConfigCommandErr(t, "Error: wait option must be an integer >= 0, got \"foo\"\n", "config", "set", "wait", "foo")
@@ -39,6 +39,12 @@ func TestConfig(t *testing.T) {
assertConfigCommand(t, "", "config", "set", "quiet", "true")
assertConfigCommand(t, "", "config", "set", "quiet", "false")
+
+ assertConfigCommand(t, "", "config", "set", "instance", "i2")
+ assertConfigCommand(t, "instance = i2\n", "config", "get", "instance")
+
+ assertConfigCommand(t, "", "config", "set", "application", "t1.a1")
+ assertConfigCommand(t, "application = t1.a1.default\n", "config", "get", "application")
}
func assertConfigCommand(t *testing.T, expected string, args ...string) {
diff --git a/client/go/cmd/root.go b/client/go/cmd/root.go
index eff399dd6e9..5fc756db037 100644
--- a/client/go/cmd/root.go
+++ b/client/go/cmd/root.go
@@ -27,6 +27,7 @@ import (
const (
applicationFlag = "application"
+ instanceFlag = "instance"
targetFlag = "target"
waitFlag = "wait"
colorFlag = "color"
@@ -58,6 +59,7 @@ type CLI struct {
type Flags struct {
target string
application string
+ instance string
waitSecs int
color string
quiet bool
@@ -151,11 +153,12 @@ func (c *CLI) loadConfig() error {
bindings := NewConfigBindings()
bindings.bindFlag(targetFlag, c.cmd)
bindings.bindFlag(applicationFlag, c.cmd)
+ bindings.bindFlag(instanceFlag, c.cmd)
bindings.bindFlag(waitFlag, c.cmd)
bindings.bindFlag(colorFlag, c.cmd)
bindings.bindFlag(quietFlag, c.cmd)
bindings.bindFlag(apiKeyFileFlag, c.cmd)
- bindings.bindEnvironment(apiKeyFlag, "VESPA_CLI_API_KEY")
+ bindings.bindEnvironment(apiKeyFlag, "VESPA_CLI_API_KEY") // not bound to a flag because we don't want secrets in argv
bindings.bindEnvironment(apiKeyFileFlag, "VESPA_CLI_API_KEY_FILE")
config, err := loadConfig(c.Environment, bindings)
if err != nil {
@@ -197,6 +200,7 @@ func (c *CLI) configureFlags() {
flags := Flags{}
c.cmd.PersistentFlags().StringVarP(&flags.target, targetFlag, "t", "local", "The name or URL of the recipient of this command")
c.cmd.PersistentFlags().StringVarP(&flags.application, applicationFlag, "a", "", "The application to manage")
+ c.cmd.PersistentFlags().StringVarP(&flags.instance, instanceFlag, "i", "", "The instance of the application to manage")
c.cmd.PersistentFlags().IntVarP(&flags.waitSecs, waitFlag, "w", 0, "Number of seconds to wait for a service to become ready")
c.cmd.PersistentFlags().StringVarP(&flags.color, colorFlag, "c", "auto", "Whether to use colors in output.")
c.cmd.PersistentFlags().BoolVarP(&flags.quiet, quietFlag, "q", false, "Quiet mode. Only errors will be printed")
diff --git a/client/go/vespa/deploy.go b/client/go/vespa/deploy.go
index 9993a773e4f..d479c86a4c7 100644
--- a/client/go/vespa/deploy.go
+++ b/client/go/vespa/deploy.go
@@ -88,10 +88,14 @@ func (d *DeploymentOptions) url(path string) (*url.URL, error) {
func ApplicationFromString(s string) (ApplicationID, error) {
parts := strings.Split(s, ".")
- if len(parts) != 3 {
+ if len(parts) < 2 || len(parts) > 3 {
return ApplicationID{}, fmt.Errorf("invalid application: %q", s)
}
- return ApplicationID{Tenant: parts[0], Application: parts[1], Instance: parts[2]}, nil
+ instance := "default"
+ if len(parts) == 3 {
+ instance = parts[2]
+ }
+ return ApplicationID{Tenant: parts[0], Application: parts[1], Instance: instance}, nil
}
func ZoneFromString(s string) (ZoneID, error) {
diff --git a/client/go/vespa/deploy_test.go b/client/go/vespa/deploy_test.go
index b660f21e45f..f27a2f2927d 100644
--- a/client/go/vespa/deploy_test.go
+++ b/client/go/vespa/deploy_test.go
@@ -16,6 +16,10 @@ func TestApplicationFromString(t *testing.T) {
assert.Equal(t, ApplicationID{Tenant: "t1", Application: "a1", Instance: "i1"}, app)
_, err = ApplicationFromString("foo")
assert.NotNil(t, err)
+
+ app, err = ApplicationFromString("t1.a1")
+ assert.Nil(t, err)
+ assert.Equal(t, ApplicationID{Tenant: "t1", Application: "a1", Instance: "default"}, app)
}
func TestZoneFromString(t *testing.T) {