Skip to content

Commit

Permalink
refactor: connect command list printing (#2703)
Browse files Browse the repository at this point in the history
Co-authored-by: Austin Abro <[email protected]>
  • Loading branch information
phillebaba and AustinAbro321 authored Jul 10, 2024
1 parent 2ef1216 commit f2c77ef
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 92 deletions.
135 changes: 66 additions & 69 deletions src/cmd/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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)
Expand Down
4 changes: 0 additions & 4 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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-"
Expand Down
6 changes: 3 additions & 3 deletions src/internal/packager/helm/post-render.go
Original file line number Diff line number Diff line change
Expand Up @@ -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],
}
}
}
Expand Down
32 changes: 16 additions & 16 deletions src/pkg/cluster/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
38 changes: 38 additions & 0 deletions src/pkg/cluster/tunnel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down

0 comments on commit f2c77ef

Please sign in to comment.