aboutsummaryrefslogtreecommitdiffstats
path: root/client/go
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-05-19 18:36:45 +0200
committerMartin Polden <mpolden@mpolden.no>2023-05-22 09:29:43 +0200
commit0dd0d8b634fc14a1762cbe9595174694d27beec3 (patch)
treea1f0bcf432dfdcce969ad3ed81bcf894cfa4caad /client/go
parent531e4093e0a06c2868ec702c7a0a9235ad54a2c6 (diff)
Resolve target based on URL
Diffstat (limited to 'client/go')
-rw-r--r--client/go/internal/cli/cmd/api_key.go4
-rw-r--r--client/go/internal/cli/cmd/cert.go10
-rw-r--r--client/go/internal/cli/cmd/config.go2
-rw-r--r--client/go/internal/cli/cmd/config_test.go16
-rw-r--r--client/go/internal/cli/cmd/login.go4
-rw-r--r--client/go/internal/cli/cmd/logout.go4
-rw-r--r--client/go/internal/cli/cmd/root.go66
-rw-r--r--client/go/internal/vespa/system.go42
-rw-r--r--client/go/internal/vespa/target_cloud.go18
9 files changed, 113 insertions, 53 deletions
diff --git a/client/go/internal/cli/cmd/api_key.go b/client/go/internal/cli/cmd/api_key.go
index 367a515f3c3..8b3780ab82b 100644
--- a/client/go/internal/cli/cmd/api_key.go
+++ b/client/go/internal/cli/cmd/api_key.go
@@ -58,11 +58,11 @@ func doApiKey(cli *CLI, overwriteKey bool, args []string) error {
if err != nil {
return err
}
- targetType, err := cli.config.targetType()
+ targetType, err := cli.targetType()
if err != nil {
return err
}
- system, err := cli.system(targetType)
+ system, err := cli.system(targetType.name)
if err != nil {
return err
}
diff --git a/client/go/internal/cli/cmd/cert.go b/client/go/internal/cli/cmd/cert.go
index 48bad974c3f..95206b7e77d 100644
--- a/client/go/internal/cli/cmd/cert.go
+++ b/client/go/internal/cli/cmd/cert.go
@@ -107,15 +107,15 @@ func doCert(cli *CLI, overwriteCertificate, noApplicationPackage bool, args []st
return err
}
}
- targetType, err := cli.config.targetType()
+ targetType, err := cli.targetType()
if err != nil {
return err
}
- privateKeyFile, err := cli.config.privateKeyPath(app, targetType)
+ privateKeyFile, err := cli.config.privateKeyPath(app, targetType.name)
if err != nil {
return err
}
- certificateFile, err := cli.config.certificatePath(app, targetType)
+ certificateFile, err := cli.config.certificatePath(app, targetType.name)
if err != nil {
return err
}
@@ -178,11 +178,11 @@ func doCertAdd(cli *CLI, overwriteCertificate bool, args []string) error {
if err != nil {
return err
}
- targetType, err := cli.config.targetType()
+ targetType, err := cli.targetType()
if err != nil {
return err
}
- certificateFile, err := cli.config.certificatePath(app, targetType)
+ certificateFile, err := cli.config.certificatePath(app, targetType.name)
if err != nil {
return err
}
diff --git a/client/go/internal/cli/cmd/config.go b/client/go/internal/cli/cmd/config.go
index e2132814386..0e120546c8b 100644
--- a/client/go/internal/cli/cmd/config.go
+++ b/client/go/internal/cli/cmd/config.go
@@ -329,7 +329,7 @@ func (c *Config) write() error {
return c.config.WriteFile(configFile)
}
-func (c *Config) targetType() (string, error) {
+func (c *Config) targetOrURL() (string, error) {
targetType, ok := c.get(targetFlag)
if !ok {
return "", fmt.Errorf("target is unset")
diff --git a/client/go/internal/cli/cmd/config_test.go b/client/go/internal/cli/cmd/config_test.go
index 66b65bf402b..3a81b93ea0d 100644
--- a/client/go/internal/cli/cmd/config_test.go
+++ b/client/go/internal/cli/cmd/config_test.go
@@ -261,6 +261,22 @@ func TestConfigReadTLSOptions(t *testing.T) {
)
}
+func TestConfigTargetResolving(t *testing.T) {
+ cli, _, _ := newTestCLI(t)
+ require.Nil(t, cli.Run("config", "set", "target", "https://example.com"))
+ assertTargetType(t, vespa.TargetCustom, cli)
+ require.Nil(t, cli.Run("config", "set", "target", "https://foo.bar.vespa-team.no-north-1.dev.z.vespa-app.cloud"))
+ assertTargetType(t, vespa.TargetCloud, cli)
+ require.Nil(t, cli.Run("config", "set", "target", "https://foo.bar.vespa-team.no-north-1.dev.z.vespa.oath.cloud:4443"))
+ assertTargetType(t, vespa.TargetHosted, cli)
+}
+
+func assertTargetType(t *testing.T, expected string, cli *CLI) {
+ targetType, err := cli.targetType()
+ require.Nil(t, err)
+ assert.Equal(t, expected, targetType.name)
+}
+
func assertTLSOptions(t *testing.T, homeDir string, app vespa.ApplicationID, target string, want vespa.TLSOptions, envVars ...string) {
t.Helper()
envVars = append(envVars, "VESPA_CLI_HOME="+homeDir)
diff --git a/client/go/internal/cli/cmd/login.go b/client/go/internal/cli/cmd/login.go
index 9ac2262e78d..d2075bdfcf0 100644
--- a/client/go/internal/cli/cmd/login.go
+++ b/client/go/internal/cli/cmd/login.go
@@ -27,11 +27,11 @@ func newLoginCmd(cli *CLI) *cobra.Command {
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
- targetType, err := cli.config.targetType()
+ targetType, err := cli.targetType()
if err != nil {
return err
}
- system, err := cli.system(targetType)
+ system, err := cli.system(targetType.name)
if err != nil {
return err
}
diff --git a/client/go/internal/cli/cmd/logout.go b/client/go/internal/cli/cmd/logout.go
index 32e7cd9783b..93f7cb6270f 100644
--- a/client/go/internal/cli/cmd/logout.go
+++ b/client/go/internal/cli/cmd/logout.go
@@ -14,11 +14,11 @@ func newLogoutCmd(cli *CLI) *cobra.Command {
DisableAutoGenTag: true,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
- targetType, err := cli.config.targetType()
+ targetType, err := cli.targetType()
if err != nil {
return err
}
- system, err := cli.system(targetType)
+ system, err := cli.system(targetType.name)
if err != nil {
return err
}
diff --git a/client/go/internal/cli/cmd/root.go b/client/go/internal/cli/cmd/root.go
index c4012024426..17c4fc41625 100644
--- a/client/go/internal/cli/cmd/root.go
+++ b/client/go/internal/cli/cmd/root.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"log"
+ "net/url"
"os"
"os/exec"
"strings"
@@ -73,6 +74,11 @@ type targetOptions struct {
noCertificate bool
}
+type targetType struct {
+ name string
+ url string
+}
+
// errHint creates a new CLI error, with optional hints that will be printed after the error
func errHint(err error, hints ...string) ErrCLI { return ErrCLI{Status: 1, hints: hints, error: err} }
@@ -297,7 +303,19 @@ func (c *CLI) printWarning(msg interface{}, hints ...string) {
// target creates a target according the configuration of this CLI and given opts.
func (c *CLI) target(opts targetOptions) (vespa.Target, error) {
- target, err := c.createTarget(opts)
+ targetType, err := c.targetType()
+ if err != nil {
+ return nil, err
+ }
+ var target vespa.Target
+ switch targetType.name {
+ case vespa.TargetLocal, vespa.TargetCustom:
+ target, err = c.createCustomTarget(targetType.name, targetType.url)
+ case vespa.TargetCloud, vespa.TargetHosted:
+ target, err = c.createCloudTarget(targetType.name, opts, targetType.url)
+ default:
+ return nil, errHint(fmt.Errorf("invalid target: %s", targetType), "Valid targets are 'local', 'cloud', 'hosted' or an URL")
+ }
if err != nil {
return nil, err
}
@@ -309,24 +327,39 @@ func (c *CLI) target(opts targetOptions) (vespa.Target, error) {
return target, nil
}
-func (c *CLI) createTarget(opts targetOptions) (vespa.Target, error) {
- targetType, err := c.config.targetType()
+// targetType resolves the real target type and its custom URL (if any)
+func (c *CLI) targetType() (targetType, error) {
+ v, err := c.config.targetOrURL()
if err != nil {
- return nil, err
+ return targetType{}, err
}
- customURL := ""
- if strings.HasPrefix(targetType, "http") {
- customURL = targetType
- targetType = vespa.TargetCustom
+ tt := targetType{name: v}
+ if strings.HasPrefix(tt.name, "http://") || strings.HasPrefix(tt.name, "https://") {
+ tt.url = tt.name
+ tt.name, err = c.targetFromURL(tt.url)
+ if err != nil {
+ return targetType{}, err
+ }
}
- switch targetType {
- case vespa.TargetLocal, vespa.TargetCustom:
- return c.createCustomTarget(targetType, customURL)
- case vespa.TargetCloud, vespa.TargetHosted:
- return c.createCloudTarget(targetType, opts)
- default:
- return nil, errHint(fmt.Errorf("invalid target: %s", targetType), "Valid targets are 'local', 'cloud', 'hosted' or an URL")
+ return tt, nil
+}
+
+func (c *CLI) targetFromURL(customURL string) (string, error) {
+ u, err := url.Parse(customURL)
+ if err != nil {
+ return "", err
+ }
+ // Check if URL belongs to a cloud target
+ for _, cloudTarget := range []string{vespa.TargetHosted, vespa.TargetCloud} {
+ system, err := c.system(cloudTarget)
+ if err != nil {
+ return "", err
+ }
+ if strings.HasSuffix(u.Hostname(), "."+system.EndpointDomain) {
+ return cloudTarget, nil
+ }
}
+ return vespa.TargetCustom, nil
}
func (c *CLI) createCustomTarget(targetType, customURL string) (vespa.Target, error) {
@@ -344,7 +377,7 @@ func (c *CLI) createCustomTarget(targetType, customURL string) (vespa.Target, er
}
}
-func (c *CLI) createCloudTarget(targetType string, opts targetOptions) (vespa.Target, error) {
+func (c *CLI) createCloudTarget(targetType string, opts targetOptions, customURL string) (vespa.Target, error) {
system, err := c.system(targetType)
if err != nil {
return nil, err
@@ -409,6 +442,7 @@ func (c *CLI) createCloudTarget(targetType string, opts targetOptions) (vespa.Ta
deploymentOptions := vespa.CloudDeploymentOptions{
Deployment: deployment,
TLSOptions: deploymentTLSOptions,
+ CustomURL: customURL,
ClusterURLs: endpoints,
}
logLevel := opts.logLevel
diff --git a/client/go/internal/vespa/system.go b/client/go/internal/vespa/system.go
index b8263dbdec0..96795cc0ef8 100644
--- a/client/go/internal/vespa/system.go
+++ b/client/go/internal/vespa/system.go
@@ -4,36 +4,40 @@ import "fmt"
// PublicSystem represents the main Vespa Cloud system.
var PublicSystem = System{
- Name: "public",
- URL: "https://api-ctl.vespa-cloud.com:4443",
- ConsoleURL: "https://console.vespa-cloud.com",
- DefaultZone: ZoneID{Environment: "dev", Region: "aws-us-east-1c"},
+ Name: "public",
+ URL: "https://api-ctl.vespa-cloud.com:4443",
+ ConsoleURL: "https://console.vespa-cloud.com",
+ DefaultZone: ZoneID{Environment: "dev", Region: "aws-us-east-1c"},
+ EndpointDomain: "vespa-app.cloud",
}
// PublicCDSystem represents the CD variant of the Vespa Cloud system.
var PublicCDSystem = System{
- Name: "publiccd",
- URL: "https://api-ctl.cd.vespa-cloud.com:4443",
- ConsoleURL: "https://console.cd.vespa-cloud.com",
- DefaultZone: ZoneID{Environment: "dev", Region: "aws-us-east-1c"},
+ Name: "publiccd",
+ URL: "https://api-ctl.cd.vespa-cloud.com:4443",
+ ConsoleURL: "https://console.cd.vespa-cloud.com",
+ DefaultZone: ZoneID{Environment: "dev", Region: "aws-us-east-1c"},
+ EndpointDomain: "cd.vespa-app.cloud",
}
// MainSystem represents the main hosted Vespa system.
var MainSystem = System{
- Name: "main",
- URL: "https://api.vespa.ouryahoo.com:4443",
- ConsoleURL: "https://console.vespa.ouryahoo.com",
- DefaultZone: ZoneID{Environment: "dev", Region: "us-east-1"},
- AthenzDomain: "vespa.vespa",
+ Name: "main",
+ URL: "https://api.vespa.ouryahoo.com:4443",
+ ConsoleURL: "https://console.vespa.ouryahoo.com",
+ DefaultZone: ZoneID{Environment: "dev", Region: "us-east-1"},
+ AthenzDomain: "vespa.vespa",
+ EndpointDomain: "vespa.oath.cloud",
}
// CDSystem represents the CD variant of the hosted Vespa system.
var CDSystem = System{
- Name: "cd",
- URL: "https://api-cd.vespa.ouryahoo.com:4443",
- ConsoleURL: "https://console-cd.vespa.ouryahoo.com",
- DefaultZone: ZoneID{Environment: "dev", Region: "cd-us-west-1"},
- AthenzDomain: "vespa.vespa.cd",
+ Name: "cd",
+ URL: "https://api-cd.vespa.ouryahoo.com:4443",
+ ConsoleURL: "https://console-cd.vespa.ouryahoo.com",
+ DefaultZone: ZoneID{Environment: "dev", Region: "cd-us-west-1"},
+ AthenzDomain: "vespa.vespa.cd",
+ EndpointDomain: "cd.vespa.oath.cloud",
}
// System represents a Vespa system.
@@ -47,6 +51,8 @@ type System struct {
// AthenzDomain is the Athenz domain used by this system. This is empty for systems not using Athenz for tenant
// authentication.
AthenzDomain string
+ // EndpointDomain is the domain used for application endpoints in this system
+ EndpointDomain string
}
// IsPublic returns whether system s is a public (Vespa Cloud) system.
diff --git a/client/go/internal/vespa/target_cloud.go b/client/go/internal/vespa/target_cloud.go
index 928bb788494..c0169f1a9bd 100644
--- a/client/go/internal/vespa/target_cloud.go
+++ b/client/go/internal/vespa/target_cloud.go
@@ -26,6 +26,7 @@ type APIOptions struct {
type CloudDeploymentOptions struct {
Deployment Deployment
TLSOptions TLSOptions
+ CustomURL string
ClusterURLs map[string]string // Endpoints keyed on cluster name
}
@@ -73,7 +74,15 @@ func CloudTarget(httpClient util.HTTPClient, apiAuth Authenticator, deploymentAu
}, nil
}
-func (t *cloudTarget) findClusterURL(cluster string) (string, error) {
+func (t *cloudTarget) findClusterURL(cluster string, timeout time.Duration, runID int64) (string, error) {
+ if t.deploymentOptions.CustomURL != "" {
+ return t.deploymentOptions.CustomURL, nil
+ }
+ if t.deploymentOptions.ClusterURLs == nil {
+ if err := t.waitForEndpoints(timeout, runID); err != nil {
+ return "", err
+ }
+ }
clusters := make([]string, 0, len(t.deploymentOptions.ClusterURLs))
for c := range t.deploymentOptions.ClusterURLs {
clusters = append(clusters, c)
@@ -129,12 +138,7 @@ func (t *cloudTarget) Service(name string, timeout time.Duration, runID int64, c
}
return service, nil
case QueryService, DocumentService:
- if t.deploymentOptions.ClusterURLs == nil {
- if err := t.waitForEndpoints(timeout, runID); err != nil {
- return nil, err
- }
- }
- url, err := t.findClusterURL(cluster)
+ url, err := t.findClusterURL(cluster, timeout, runID)
if err != nil {
return nil, err
}