Skip to content

Commit

Permalink
Added tests for new Kubernetes selector behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
timothyb89 committed Jan 10, 2025
1 parent ca0c4e8 commit 2204e0a
Show file tree
Hide file tree
Showing 7 changed files with 530 additions and 16 deletions.
85 changes: 85 additions & 0 deletions lib/tbot/cli/start_kubernetes_v2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package cli

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/lib/tbot/config"
)

// TestKubernetesV2Command tests that the KubernetesCommand properly parses its
// arguments and applies as expected onto a BotConfig.
func TestKubernetesV2Command(t *testing.T) {
testStartConfigureCommand(t, NewKubernetesV2Command, []startConfigureTestCase{
{
name: "success",
args: []string{
"start",
"kubernetes/v2",
"--destination=/bar",
"--token=foo",
"--join-method=github",
"--proxy-server=example.com:443",
"--disable-exec-plugin",
"--kubernetes-cluster-name=a",
"--kubernetes-cluster-name=b",
"--kubernetes-cluster-labels=c=\"foo bar\",d=\"baz qux\"",
},
assertConfig: func(t *testing.T, cfg *config.BotConfig) {
require.Len(t, cfg.Services, 1)

// It must configure a kubernetes output with a directory destination.
svc := cfg.Services[0]
k8s, ok := svc.(*config.KubernetesV2Output)
require.True(t, ok)

require.True(t, k8s.DisableExecPlugin)

dir, ok := k8s.Destination.(*config.DestinationDirectory)
require.True(t, ok)
require.Equal(t, "/bar", dir.Path)

var foundA, foundB, foundLabelSelector bool
for _, selector := range k8s.Selectors {
switch selector.Name {
case "a":
foundA = true
case "b":
foundB = true
case "":
require.Equal(t, map[string]string{
"c": "foo bar",
"d": "baz qux",
}, selector.Labels)
foundLabelSelector = true
default:
require.Fail(t, "unexpected selector name %q", selector.Name)
}
}

require.True(t, foundA, "name selector 'a' must exist")
require.True(t, foundB, "name selector 'b' must exist")
require.True(t, foundLabelSelector, "label selector must exist")
},
},
})
}
2 changes: 1 addition & 1 deletion lib/tbot/service_kubernetes_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ func chooseOneKubeCluster(clusters []types.KubeCluster, name string) (types.Kube
return chooseOneResource(clusters, name, "kubernetes cluster")
}

func getKubeCluster(ctx context.Context, clt *authclient.Client, name string) (types.KubeCluster, error) {
func getKubeCluster(ctx context.Context, clt apiclient.GetResourcesClient, name string) (types.KubeCluster, error) {
ctx, span := tracer.Start(ctx, "getKubeCluster")
defer span.End()

Expand Down
22 changes: 7 additions & 15 deletions lib/tbot/service_kubernetes_v2_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils"
"github.com/gravitational/teleport/lib/auth/authclient"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/kube/kubeconfig"
Expand Down Expand Up @@ -142,10 +143,12 @@ func (s *KubernetesV2OutputService) generate(ctx context.Context) error {
clusterNames = append(clusterNames, c.GetName())
}

clusterNames = utils.Deduplicate(clusterNames)

s.log.InfoContext(
ctx,
"Generated identity for Kubernetes access",
"matched_cluster_count", len(clusters),
"matched_cluster_count", len(clusterNames),
"identity", describeTLSIdentity(ctx, s.log, id),
)

Expand All @@ -163,18 +166,6 @@ func (s *KubernetesV2OutputService) generate(ctx context.Context) error {
if err != nil {
return trace.Wrap(err)
}
// TODO(noah): It's likely the Kubernetes output does not really need to
// output these CAs - but - for backwards compat reasons, we output them.
// Revisit this at a later date and make a call.
// TODO(tim): If we don't need these, we'll drop them from V2.
// userCAs, err := s.botAuthClient.GetCertAuthorities(ctx, types.UserCA, false)
// if err != nil {
// return trace.Wrap(err)
// }
// databaseCAs, err := s.botAuthClient.GetCertAuthorities(ctx, types.DatabaseCA, false)
// if err != nil {
// return trace.Wrap(err)
// }

keyRing, err := NewClientKeyRing(id, hostCAs)
if err != nil {
Expand Down Expand Up @@ -204,7 +195,7 @@ type kubernetesStatusV2 struct {

// queryKubeClustersByLabels fetches a list of Kubernetes clusters matching the
// given label selector.
func queryKubeClustersByLabels(ctx context.Context, clt *authclient.Client, labels map[string]string) ([]types.KubeCluster, error) {
func queryKubeClustersByLabels(ctx context.Context, clt apiclient.GetResourcesClient, labels map[string]string) ([]types.KubeCluster, error) {
ctx, span := tracer.Start(ctx, "queryKubeClustersByLabels")
defer span.End()

Expand All @@ -227,7 +218,7 @@ func queryKubeClustersByLabels(ctx context.Context, clt *authclient.Client, labe

// fetchAllMatchingKubeClusters returns a list of all clusters matching the
// given selectors.
func fetchAllMatchingKubeClusters(ctx context.Context, clt *authclient.Client, selectors []*config.KubernetesSelector) ([]types.KubeCluster, error) {
func fetchAllMatchingKubeClusters(ctx context.Context, clt apiclient.GetResourcesClient, selectors []*config.KubernetesSelector) ([]types.KubeCluster, error) {
ctx, span := tracer.Start(ctx, "findAllMatchingKubeClusters")
defer span.End()

Expand Down Expand Up @@ -281,6 +272,7 @@ func (s *KubernetesV2OutputService) render(
); err != nil {
return trace.Wrap(err, "persisting identity")
}

// In exec plugin mode, we write the credentials to disk and write a
// kubeconfig that execs `tbot` to load those credentials.

Expand Down
Loading

0 comments on commit 2204e0a

Please sign in to comment.