Skip to content

Commit

Permalink
fix: override tunnel details with user-provided settings (#2841)
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Seagren <timseagren@defenseunicorns.com>
  • Loading branch information
chaospuppy authored Aug 6, 2024
1 parent ee60eb8 commit 7e42b5d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 66 deletions.
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
38 changes: 22 additions & 16 deletions src/cmd/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@ import (
)

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

var connectCmd = &cobra.Command{
Use: "connect { REGISTRY | GIT | connect-name }",
Aliases: []string{"c"},
Expand All @@ -46,15 +41,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 +68,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 +107,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."
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

0 comments on commit 7e42b5d

Please sign in to comment.