diff --git a/src/cmd/connect.go b/src/cmd/connect.go index 7111abf813..89eb341b45 100644 --- a/src/cmd/connect.go +++ b/src/cmd/connect.go @@ -5,14 +5,14 @@ package cmd import ( - "context" "fmt" + "github.com/spf13/cobra" + "github.com/defenseunicorns/zarf/src/config/lang" "github.com/defenseunicorns/zarf/src/pkg/cluster" "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/utils/exec" - "github.com/spf13/cobra" ) var ( @@ -22,83 +22,80 @@ var ( connectLocalPort int connectRemotePort int cliOnly bool +) - connectCmd = &cobra.Command{ - Use: "connect { REGISTRY | GIT | connect-name }", - Aliases: []string{"c"}, - Short: lang.CmdConnectShort, - Long: lang.CmdConnectLong, - RunE: func(cmd *cobra.Command, args []string) error { - var target string - if len(args) > 0 { - target = args[0] - } - spinner := message.NewProgressSpinner(lang.CmdConnectPreparingTunnel, target) - defer spinner.Stop() - c, err := cluster.NewCluster() - if err != nil { - return err - } +var connectCmd = &cobra.Command{ + Use: "connect { REGISTRY | GIT | connect-name }", + Aliases: []string{"c"}, + Short: lang.CmdConnectShort, + Long: lang.CmdConnectLong, + RunE: func(cmd *cobra.Command, args []string) error { + target := "" + if len(args) > 0 { + target = args[0] + } - ctx := cmd.Context() + spinner := message.NewProgressSpinner(lang.CmdConnectPreparingTunnel, target) + defer spinner.Stop() - var tunnel *cluster.Tunnel - if connectResourceName != "" { - zt := cluster.NewTunnelInfo(connectNamespace, connectResourceType, connectResourceName, "", connectLocalPort, connectRemotePort) - tunnel, err = c.ConnectTunnelInfo(ctx, zt) - } else { - tunnel, err = c.Connect(ctx, target) - } - if err != nil { - return fmt.Errorf("unable to connect to the service: %w", err) - } + c, err := cluster.NewCluster() + if err != nil { + return err + } - defer tunnel.Close() - url := tunnel.FullURL() + ctx := cmd.Context() - // Dump the tunnel URL to the console for other tools to use. - fmt.Print(url) + var tunnel *cluster.Tunnel + if connectResourceName == "" { + tunnel, err = c.Connect(ctx, target) + } else { + zt := cluster.NewTunnelInfo(connectNamespace, connectResourceType, connectResourceName, "", connectLocalPort, connectRemotePort) + tunnel, err = c.ConnectTunnelInfo(ctx, zt) + } + if err != nil { + return fmt.Errorf("unable to connect to the service: %w", err) + } + defer tunnel.Close() - if cliOnly { - spinner.Updatef(lang.CmdConnectEstablishedCLI, url) - } else { - spinner.Updatef(lang.CmdConnectEstablishedWeb, url) + // Dump the tunnel URL to the console for other tools to use. + fmt.Print(tunnel.FullURL()) - if err := exec.LaunchURL(url); err != nil { - message.Debug(err) - } + if cliOnly { + 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, url) - case err = <-tunnel.ErrChan(): - return fmt.Errorf("lost connection to the service: %w", err) - } - return nil - }, - } - - connectListCmd = &cobra.Command{ - Use: "list", - Aliases: []string{"l"}, - Short: lang.CmdConnectListShort, - RunE: func(cmd *cobra.Command, _ []string) error { - timeoutCtx, cancel := context.WithTimeout(cmd.Context(), cluster.DefaultTimeout) - defer cancel() - c, err := cluster.NewClusterWithWait(timeoutCtx) - if err != nil { - return err - } - err = c.PrintConnectTable(cmd.Context()) - if err != nil { - return err - } + select { + case <-ctx.Done(): + spinner.Successf(lang.CmdConnectTunnelClosed, tunnel.FullURL()) return nil - }, - } -) + case err = <-tunnel.ErrChan(): + return fmt.Errorf("lost connection to the service: %w", err) + } + }, +} + +var connectListCmd = &cobra.Command{ + Use: "list", + Aliases: []string{"l"}, + Short: lang.CmdConnectListShort, + RunE: func(cmd *cobra.Command, _ []string) error { + c, err := cluster.NewCluster() + if err != nil { + return err + } + connections, err := c.ListConnections(cmd.Context()) + if err != nil { + return err + } + message.PrintConnectStringTable(connections) + return nil + }, +} func init() { rootCmd.AddCommand(connectCmd) diff --git a/src/config/config.go b/src/config/config.go index d3b0c07a21..f9dfc580ab 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -21,10 +21,6 @@ const ( ZarfAgentHost = "agent-hook.zarf.svc" - ZarfConnectLabelName = "zarf.dev/connect-name" - ZarfConnectAnnotationDescription = "zarf.dev/connect-description" - ZarfConnectAnnotationURL = "zarf.dev/connect-url" - ZarfCleanupScriptsPath = "/opt/zarf" ZarfPackagePrefix = "zarf-package-" diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go index 43bc102a6b..b03aa6a93a 100644 --- a/src/internal/packager/helm/post-render.go +++ b/src/internal/packager/helm/post-render.go @@ -254,14 +254,14 @@ func (r *renderer) editHelmResources(ctx context.Context, resources []releaseuti if annotations == nil { annotations = map[string]string{} } - if key, keyExists := labels[config.ZarfConnectLabelName]; keyExists { + if key, keyExists := labels[cluster.ZarfConnectLabelName]; keyExists { // If there is a zarf-connect label message.Debugf("Match helm service %s for zarf connection %s", rawData.GetName(), key) // Add the connectString for processing later in the deployment r.connectStrings[key] = types.ConnectString{ - Description: annotations[config.ZarfConnectAnnotationDescription], - URL: annotations[config.ZarfConnectAnnotationURL], + Description: annotations[cluster.ZarfConnectAnnotationDescription], + URL: annotations[cluster.ZarfConnectAnnotationURL], } } } diff --git a/src/pkg/cluster/tunnel.go b/src/pkg/cluster/tunnel.go index 10a287986d..3f8433ed9f 100644 --- a/src/pkg/cluster/tunnel.go +++ b/src/pkg/cluster/tunnel.go @@ -23,13 +23,16 @@ import ( "k8s.io/client-go/transport/spdy" "github.com/defenseunicorns/pkg/helpers/v2" - "github.com/defenseunicorns/zarf/src/config" "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/types" ) // Zarf specific connect strings const ( + ZarfConnectLabelName = "zarf.dev/connect-name" + ZarfConnectAnnotationDescription = "zarf.dev/connect-description" + ZarfConnectAnnotationURL = "zarf.dev/connect-url" + ZarfRegistry = "REGISTRY" ZarfGit = "GIT" ZarfInjector = "INJECTOR" @@ -64,33 +67,30 @@ func NewTunnelInfo(namespace, resourceType, resourceName, urlSuffix string, loca } } -// PrintConnectTable will print a table of all Zarf connect matches found in the cluster. -func (c *Cluster) PrintConnectTable(ctx context.Context) error { +// 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{ MatchExpressions: []metav1.LabelSelectorRequirement{{ Operator: metav1.LabelSelectorOpExists, - Key: config.ZarfConnectLabelName, + Key: ZarfConnectLabelName, }}, }) if err != nil { - return err + return nil, err } serviceList, err := c.Clientset.CoreV1().Services("").List(ctx, metav1.ListOptions{LabelSelector: selector.String()}) if err != nil { - return err + return nil, err } - - connections := make(types.ConnectStrings) + connections := types.ConnectStrings{} for _, svc := range serviceList.Items { - name := svc.Labels[config.ZarfConnectLabelName] - // Add the connectString for processing later in the deployment. + name := svc.Labels[ZarfConnectLabelName] connections[name] = types.ConnectString{ - Description: svc.Annotations[config.ZarfConnectAnnotationDescription], - URL: svc.Annotations[config.ZarfConnectAnnotationURL], + Description: svc.Annotations[ZarfConnectAnnotationDescription], + URL: svc.Annotations[ZarfConnectAnnotationURL], } } - message.PrintConnectStringTable(connections) - return nil + return connections, nil } // Connect will establish a tunnel to the specified target. @@ -189,7 +189,7 @@ func (c *Cluster) checkForZarfConnectLabel(ctx context.Context, name string) (Tu selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ MatchLabels: map[string]string{ - config.ZarfConnectLabelName: name, + ZarfConnectLabelName: name, }, }) if err != nil { @@ -222,7 +222,7 @@ func (c *Cluster) checkForZarfConnectLabel(ctx context.Context, name string) (Tu } // Add the url suffix too. - zt.urlSuffix = svc.Annotations[config.ZarfConnectAnnotationURL] + zt.urlSuffix = svc.Annotations[ZarfConnectAnnotationURL] message.Debugf("tunnel connection match: %s/%s on port %d", svc.Namespace, svc.Name, zt.remotePort) } else { diff --git a/src/pkg/cluster/tunnel_test.go b/src/pkg/cluster/tunnel_test.go index f9dfc7b5c8..fd1866da19 100644 --- a/src/pkg/cluster/tunnel_test.go +++ b/src/pkg/cluster/tunnel_test.go @@ -4,13 +4,51 @@ package cluster import ( + "context" "testing" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + + "github.com/defenseunicorns/zarf/src/types" ) +func TestListConnections(t *testing.T) { + t.Parallel() + + c := &Cluster{ + Clientset: fake.NewSimpleClientset(), + } + svc := corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "connect", + Labels: map[string]string{ + ZarfConnectLabelName: "connect name", + }, + Annotations: map[string]string{ + ZarfConnectAnnotationDescription: "description", + ZarfConnectAnnotationURL: "url", + }, + }, + Spec: corev1.ServiceSpec{}, + } + _, err := c.Clientset.CoreV1().Services(svc.ObjectMeta.Namespace).Create(context.Background(), &svc, metav1.CreateOptions{}) + require.NoError(t, err) + + connections, err := c.ListConnections(context.Background()) + require.NoError(t, err) + expectedConnections := types.ConnectStrings{ + "connect name": types.ConnectString{ + Description: "description", + URL: "url", + }, + } + require.Equal(t, expectedConnections, connections) +} + func TestServiceInfoFromNodePortURL(t *testing.T) { t.Parallel()