From 270b58aadb6af7fdd9dcadd09ee517cdbf1f3e20 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 30 Jun 2022 09:59:20 +0200 Subject: Support specifying cluster name --- client/go/cmd/config.go | 16 ++++++++++++++++ client/go/cmd/config_test.go | 6 ++++++ client/go/cmd/curl.go | 2 +- client/go/cmd/curl_test.go | 1 + client/go/cmd/deploy.go | 2 +- client/go/cmd/document.go | 2 +- client/go/cmd/query.go | 2 +- client/go/cmd/root.go | 7 +++++-- client/go/cmd/status.go | 2 +- client/go/vespa/target_cloud.go | 30 +++++++++++++++--------------- 10 files changed, 48 insertions(+), 22 deletions(-) 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 = \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 = \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 = 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 461c2ea5bf0..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"`) 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 } -- cgit v1.2.3