Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: override tunnel details with user-provided settings #2707

Closed
wants to merge 9 commits into from
10 changes: 5 additions & 5 deletions site/src/content/docs/commands/zarf_connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ zarf connect { REGISTRY | GIT | connect-name } [flags]
```
--cli-only Disable browser auto-open
-h, --help help for connect
--local-port int (Optional, autogenerated if not provided) Specify the local port to bind to. E.g. local-port=42000. Ignored if --name is unset.
--name string Specify the resource name. E.g. name=unicorns or name=unicorn-pod-7448499f4d-b5bk6.
--namespace string Specify the namespace. E.g. namespace=default. Ignored if --name is unset. (default "zarf")
--remote-port int Specify the remote port of the resource to bind to. E.g. remote-port=8080. Ignored if --name is unset.
--type string Specify the resource type. E.g. type=svc or type=pod. Ignored if --name is unset. (default "svc")
--local-port int (Optional, autogenerated if not provided) Specify the local port to bind to. E.g. local-port=42000.
--name string Specify the resource name. E.g. name=unicorns or name=unicorn-pod-7448499f4d-b5bk6. Ignored if connect-name is supplied.
--namespace string Specify the namespace. E.g. namespace=default. Ignored if connect-name is supplied. (default "zarf")
--remote-port int Specify the remote port of the resource to bind to. E.g. remote-port=8080. Ignored if connect-name is supplied.
--type string Specify the resource type. E.g. type=svc or type=pod. Ignored if connect-name is supplied. (default "svc")
```

### Options inherited from parent commands
Expand Down
37 changes: 22 additions & 15 deletions src/cmd/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@ import (
)

var (
connectResourceName string
connectNamespace string
connectResourceType string
connectLocalPort int
connectRemotePort int
cliOnly bool
cliOnly bool
zt cluster.TunnelInfo
)

var connectCmd = &cobra.Command{
Expand All @@ -46,15 +42,24 @@ var connectCmd = &cobra.Command{
ctx := cmd.Context()

var tunnel *cluster.Tunnel
if connectResourceName == "" {
tunnel, err = c.Connect(ctx, target)
} else {
zt := cluster.NewTunnelInfo(connectNamespace, connectResourceType, connectResourceName, "", connectLocalPort, connectRemotePort)
if target == "" {
tunnel, err = c.ConnectTunnelInfo(ctx, zt)
} else {
var ti cluster.TunnelInfo
ti, err = c.NewTargetTunnelInfo(ctx, target)
if err != nil {
return fmt.Errorf("unable to create tunnel: %w", err)
}
if zt.LocalPort != 0 {
ti.LocalPort = zt.LocalPort
}
tunnel, err = c.ConnectTunnelInfo(ctx, ti)
}

if err != nil {
return fmt.Errorf("unable to connect to the service: %w", err)
}

defer tunnel.Close()

// Dump the tunnel URL to the console for other tools to use.
Expand All @@ -64,11 +69,13 @@ var connectCmd = &cobra.Command{
spinner.Updatef(lang.CmdConnectEstablishedCLI, tunnel.FullURL())
} else {
spinner.Updatef(lang.CmdConnectEstablishedWeb, tunnel.FullURL())

if err := exec.LaunchURL(tunnel.FullURL()); err != nil {
message.Debug(err)
}
}

// Wait for the interrupt signal or an error.
select {
case <-ctx.Done():
spinner.Successf(lang.CmdConnectTunnelClosed, tunnel.FullURL())
Expand Down Expand Up @@ -101,10 +108,10 @@ func init() {
rootCmd.AddCommand(connectCmd)
connectCmd.AddCommand(connectListCmd)

connectCmd.Flags().StringVar(&connectResourceName, "name", "", lang.CmdConnectFlagName)
connectCmd.Flags().StringVar(&connectNamespace, "namespace", cluster.ZarfNamespaceName, lang.CmdConnectFlagNamespace)
connectCmd.Flags().StringVar(&connectResourceType, "type", cluster.SvcResource, lang.CmdConnectFlagType)
connectCmd.Flags().IntVar(&connectLocalPort, "local-port", 0, lang.CmdConnectFlagLocalPort)
connectCmd.Flags().IntVar(&connectRemotePort, "remote-port", 0, lang.CmdConnectFlagRemotePort)
connectCmd.Flags().StringVar(&zt.ResourceName, "name", "", lang.CmdConnectFlagName)
connectCmd.Flags().StringVar(&zt.Namespace, "namespace", cluster.ZarfNamespaceName, lang.CmdConnectFlagNamespace)
connectCmd.Flags().StringVar(&zt.ResourceType, "type", cluster.SvcResource, lang.CmdConnectFlagType)
connectCmd.Flags().IntVar(&zt.LocalPort, "local-port", 0, lang.CmdConnectFlagLocalPort)
connectCmd.Flags().IntVar(&zt.RemotePort, "remote-port", 0, lang.CmdConnectFlagRemotePort)
connectCmd.Flags().BoolVar(&cliOnly, "cli-only", false, lang.CmdConnectFlagCliOnly)
}
10 changes: 5 additions & 5 deletions src/config/lang/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ const (
// zarf connect list
CmdConnectListShort = "Lists all available connection shortcuts"

CmdConnectFlagName = "Specify the resource name. E.g. name=unicorns or name=unicorn-pod-7448499f4d-b5bk6."
CmdConnectFlagNamespace = "Specify the namespace. E.g. namespace=default. Ignored if --name is unset."
CmdConnectFlagType = "Specify the resource type. E.g. type=svc or type=pod. Ignored if --name is unset."
CmdConnectFlagLocalPort = "(Optional, autogenerated if not provided) Specify the local port to bind to. E.g. local-port=42000. Ignored if --name is unset."
CmdConnectFlagRemotePort = "Specify the remote port of the resource to bind to. E.g. remote-port=8080. Ignored if --name is unset."
chaospuppy marked this conversation as resolved.
Show resolved Hide resolved
CmdConnectFlagName = "Specify the resource name. E.g. name=unicorns or name=unicorn-pod-7448499f4d-b5bk6. Ignored if connect-name is supplied."
CmdConnectFlagNamespace = "Specify the namespace. E.g. namespace=default. Ignored if connect-name is supplied."
CmdConnectFlagType = "Specify the resource type. E.g. type=svc or type=pod. Ignored if connect-name is supplied."
CmdConnectFlagLocalPort = "(Optional, autogenerated if not provided) Specify the local port to bind to. E.g. local-port=42000."
CmdConnectFlagRemotePort = "Specify the remote port of the resource to bind to. E.g. remote-port=8080. Ignored if connect-name is supplied."
CmdConnectFlagCliOnly = "Disable browser auto-open"

CmdConnectPreparingTunnel = "Preparing a tunnel to connect to %s"
Expand Down
77 changes: 37 additions & 40 deletions src/pkg/cluster/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,14 @@ const (

// TunnelInfo is a struct that contains the necessary info to create a new Tunnel
type TunnelInfo struct {
localPort int
remotePort int
namespace string
resourceType string
resourceName string
LocalPort int
RemotePort int
Namespace string
ResourceType string
ResourceName string
urlSuffix string
}

// NewTunnelInfo returns a new TunnelInfo object for connecting to a cluster
func NewTunnelInfo(namespace, resourceType, resourceName, urlSuffix string, localPort, remotePort int) TunnelInfo {
return TunnelInfo{
namespace: namespace,
resourceType: resourceType,
resourceName: resourceName,
urlSuffix: urlSuffix,
localPort: localPort,
remotePort: remotePort,
}
}

// ListConnections will return a list of all Zarf connect matches found in the cluster.
func (c *Cluster) ListConnections(ctx context.Context) (types.ConnectStrings, error) {
selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{
Expand All @@ -93,44 +81,53 @@ func (c *Cluster) ListConnections(ctx context.Context) (types.ConnectStrings, er
return connections, nil
}

// Connect will establish a tunnel to the specified target.
func (c *Cluster) Connect(ctx context.Context, target string) (*Tunnel, error) {
// NewTargetTunnelInfo returns a new TunnelInfo object for the specified target.
func (c *Cluster) NewTargetTunnelInfo(ctx context.Context, target string) (TunnelInfo, error) {
var err error
zt := TunnelInfo{
namespace: ZarfNamespaceName,
resourceType: SvcResource,
Namespace: ZarfNamespaceName,
ResourceType: SvcResource,
}

switch strings.ToUpper(target) {
case ZarfRegistry:
zt.resourceName = ZarfRegistryName
zt.remotePort = ZarfRegistryPort
zt.ResourceName = ZarfRegistryName
zt.RemotePort = ZarfRegistryPort
zt.urlSuffix = `/v2/_catalog`
case ZarfGit:
zt.resourceName = ZarfGitServerName
zt.remotePort = ZarfGitServerPort
zt.ResourceName = ZarfGitServerName
zt.RemotePort = ZarfGitServerPort
case ZarfInjector:
zt.resourceName = ZarfInjectorName
zt.remotePort = ZarfInjectorPort
zt.ResourceName = ZarfInjectorName
zt.RemotePort = ZarfInjectorPort
default:
if target != "" {
if zt, err = c.checkForZarfConnectLabel(ctx, target); err != nil {
return nil, fmt.Errorf("problem looking for a zarf connect label in the cluster: %s", err.Error())
return TunnelInfo{}, fmt.Errorf("problem looking for a zarf connect label in the cluster: %s", err.Error())
}
}
if zt.resourceName == "" {
return nil, fmt.Errorf("missing resource name")
if zt.ResourceName == "" {
return TunnelInfo{}, fmt.Errorf("missing resource name")
}
if zt.remotePort < 1 {
return nil, fmt.Errorf("missing remote port")
if zt.RemotePort < 1 {
return TunnelInfo{}, fmt.Errorf("missing remote port")
}
}
return zt, err
}

// Connect will establish a tunnel to the specified target.
func (c *Cluster) Connect(ctx context.Context, target string) (*Tunnel, error) {
zt, err := c.NewTargetTunnelInfo(ctx, target)
if err != nil {
return nil, err
}
return c.ConnectTunnelInfo(ctx, zt)
}

// ConnectTunnelInfo connects to the cluster with the provided TunnelInfo
func (c *Cluster) ConnectTunnelInfo(ctx context.Context, zt TunnelInfo) (*Tunnel, error) {
tunnel, err := c.NewTunnel(zt.namespace, zt.resourceType, zt.resourceName, zt.urlSuffix, zt.localPort, zt.remotePort)
tunnel, err := c.NewTunnel(zt.Namespace, zt.ResourceType, zt.ResourceName, zt.urlSuffix, zt.LocalPort, zt.RemotePort)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -204,25 +201,25 @@ func (c *Cluster) checkForZarfConnectLabel(ctx context.Context, name string) (Tu
svc := serviceList.Items[0]

// Reset based on the matched params.
zt.resourceType = SvcResource
zt.resourceName = svc.Name
zt.namespace = svc.Namespace
zt.ResourceType = SvcResource
zt.ResourceName = svc.Name
zt.Namespace = svc.Namespace
// Only support a service with a single port.
zt.remotePort = svc.Spec.Ports[0].TargetPort.IntValue()
zt.RemotePort = svc.Spec.Ports[0].TargetPort.IntValue()
// if targetPort == 0, look for Port (which is required)
if zt.remotePort == 0 {
if zt.RemotePort == 0 {
// TODO: Need a check for if container port is not found
remotePort, err := c.findPodContainerPort(ctx, svc)
if err != nil {
return TunnelInfo{}, err
}
zt.remotePort = remotePort
zt.RemotePort = remotePort
}

// Add the url suffix too.
zt.urlSuffix = svc.Annotations[ZarfConnectAnnotationURL]

message.Debugf("tunnel connection match: %s/%s on port %d", svc.Namespace, svc.Name, zt.remotePort)
message.Debugf("tunnel connection match: %s/%s on port %d", svc.Namespace, svc.Name, zt.RemotePort)
} else {
return zt, fmt.Errorf("no matching services found for %s", name)
}
Expand Down