Skip to content

Commit

Permalink
ssh - completion with machine objects (#347)
Browse files Browse the repository at this point in the history
* get machine object

* add checkuserroes

* add unit test

* update

* update

* update MCM to 0.50.0

* update ssh_test

* add more machines in ssh_test

* add more machines in ssh_test

* feedback

* fix newtarget and test

* improve ssh tests

* fallback to node objects in case of errors

* PR feedback

* PR feedback

* rename sshTarget to currentTarget

---------

Co-authored-by: Peter Sutter <peter.sutter@sap.com>
  • Loading branch information
tedteng and petersutter authored Jan 10, 2024
1 parent 652906c commit a7b2f85
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 72 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/fatih/color v1.15.0
github.com/gardener/gardener v1.80.3
github.com/gardener/gardener-extension-provider-openstack v1.36.0
github.com/gardener/machine-controller-manager v0.50.0
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.1
github.com/mitchellh/go-homedir v1.1.0
Expand Down Expand Up @@ -45,7 +46,6 @@ require (
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gardener/etcd-druid v0.19.2 // indirect
github.com/gardener/hvpa-controller/api v0.5.0 // indirect
github.com/gardener/machine-controller-manager v0.48.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.2.4 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ github.com/gardener/gardener-extension-provider-openstack v1.36.0 h1:Zif2gepqRde
github.com/gardener/gardener-extension-provider-openstack v1.36.0/go.mod h1:fip83z/jRkH0kTyx0/GGTzSRgcL4hYVGi9i3x9ZROVc=
github.com/gardener/hvpa-controller/api v0.5.0 h1:f4F3O7YUrenwh4S3TgPREPiB287JjjUiUL18OqPLyAA=
github.com/gardener/hvpa-controller/api v0.5.0/go.mod h1:QQl3ELkCaki+8RhXl0FZMfvnm0WCGwGJlGmrxJj6lvM=
github.com/gardener/machine-controller-manager v0.48.1 h1:Oxr5e6gRm7P40Ds4nGlga/0nmfF7cH4rOfjthR6Mm38=
github.com/gardener/machine-controller-manager v0.48.1/go.mod h1:Axeu1Oh3agySk0oR4T+FUNax41Ni2K8tuksu8KRHuh0=
github.com/gardener/machine-controller-manager v0.50.0 h1:3dcQjzueFU1TGgprV00adjb3OCR99myTBx8DQGxywks=
github.com/gardener/machine-controller-manager v0.50.0/go.mod h1:RySZ40AgbNV/wMq60G/w49kb+okbj5Xs1A6usz5Pm/I=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
operationsv1alpha1 "github.com/gardener/gardener/pkg/apis/operations/v1alpha1"
seedmanagementv1alpha1 "github.com/gardener/gardener/pkg/apis/seedmanagement/v1alpha1"
machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes/scheme"

Expand All @@ -19,6 +20,7 @@ func main() {
utilruntime.Must(gardencorev1beta1.AddToScheme(scheme.Scheme))
utilruntime.Must(operationsv1alpha1.AddToScheme(scheme.Scheme))
utilruntime.Must(seedmanagementv1alpha1.AddToScheme(scheme.Scheme))
utilruntime.Must(machinev1alpha1.AddToScheme(scheme.Scheme))

cmd.Execute()
}
103 changes: 76 additions & 27 deletions pkg/cmd/ssh/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/gardener/gardener/pkg/utils"
gutil "github.com/gardener/gardener/pkg/utils/gardener"
"github.com/gardener/gardener/pkg/utils/secrets"
machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/crypto/ssh"
Expand Down Expand Up @@ -489,20 +490,20 @@ func (o *SSHOptions) Run(f util.Factory) error {
ctx := f.Context()
logger := klog.FromContext(ctx)

// sshTarget is the target used for the run method
sshTarget, err := manager.CurrentTarget()
// currentTarget is the target used for the run method
currentTarget, err := manager.CurrentTarget()
if err != nil {
return err
}

// create client for the garden cluster
gardenClient, err := manager.GardenClient(sshTarget.GardenName())
gardenClient, err := manager.GardenClient(currentTarget.GardenName())
if err != nil {
return err
}

if sshTarget.ShootName() == "" && sshTarget.SeedName() != "" {
shoot, err := gardenClient.GetShootOfManagedSeed(ctx, sshTarget.SeedName())
if currentTarget.ShootName() == "" && currentTarget.SeedName() != "" {
shoot, err := gardenClient.GetShootOfManagedSeed(ctx, currentTarget.SeedName())
if err != nil {
if apierrors.IsNotFound(err) {
return fmt.Errorf("cannot ssh to non-managed seeds: %w", err)
Expand All @@ -516,28 +517,28 @@ func (o *SSHOptions) Run(f util.Factory) error {
Namespace: "garden",
Name: shoot.Name,
},
"seed", sshTarget.SeedName())
"seed", currentTarget.SeedName())

sshTarget = sshTarget.WithProjectName("garden").WithShootName(shoot.Name)
currentTarget = currentTarget.WithProjectName("garden").WithShootName(shoot.Name)
}

if sshTarget.ShootName() == "" {
if currentTarget.ShootName() == "" {
return target.ErrNoShootTargeted
}

printTargetInformation(logger, sshTarget)
printTargetInformation(logger, currentTarget)

// fetch targeted shoot (ctx is cancellable to stop the keep alive goroutine later)
ctx, cancel := context.WithCancel(ctx)
defer cancel()

shoot, err := gardenClient.FindShoot(ctx, sshTarget.AsListOption())
shoot, err := gardenClient.FindShoot(ctx, currentTarget.AsListOption())
if err != nil {
return err
}

// check access restrictions
ok, err := o.checkAccessRestrictions(manager.Configuration(), sshTarget.GardenName(), f.TargetFlags(), shoot)
ok, err := o.checkAccessRestrictions(manager.Configuration(), currentTarget.GardenName(), f.TargetFlags(), shoot)
if err != nil {
return err
} else if !ok {
Expand Down Expand Up @@ -567,7 +568,7 @@ func (o *SSHOptions) Run(f util.Factory) error {
nodePrivateKeyFiles = append(nodePrivateKeyFiles, PrivateKeyFile(filename))
}

shootClient, err := manager.ShootClient(ctx, sshTarget)
shootClient, err := manager.ShootClient(ctx, currentTarget)
if err != nil {
return err
}
Expand Down Expand Up @@ -820,13 +821,9 @@ func cleanup(ctx context.Context, o *SSHOptions, gardenClient client.Client, bas
}
}

func getNodeNamesFromShoot(f util.Factory, prefix string) ([]string, error) {
manager, err := f.Manager()
if err != nil {
return nil, err
}
func getNodeNamesFromMachinesOrNodes(ctx context.Context, manager target.Manager) ([]string, error) {
logger := klog.FromContext(ctx)

// validate the current target
currentTarget, err := manager.CurrentTarget()
if err != nil {
return nil, err
Expand All @@ -836,25 +833,68 @@ func getNodeNamesFromShoot(f util.Factory, prefix string) ([]string, error) {
return nil, errors.New("no Shoot cluster targeted")
}

// create client for the shoot cluster
shootClient, err := manager.ShootClient(f.Context(), currentTarget)
nodeNames, err := getNodeNamesFromMachines(ctx, manager, currentTarget)
if err != nil {
if !apierrors.IsForbidden(err) {
logger.Info("failed to fetch node names from machine objects", "err", err)
}

return getNodeNamesFromNodes(ctx, manager, currentTarget)
}

return nodeNames, nil
}

func getNodeNamesFromMachines(ctx context.Context, manager target.Manager, currentTarget target.Target) ([]string, error) {
gardenClient, err := manager.GardenClient(currentTarget.GardenName())
if err != nil {
return nil, fmt.Errorf("failed to create garden cluster client: %w", err)
}

shoot, err := gardenClient.FindShoot(ctx, currentTarget.AsListOption())
if err != nil {
return nil, err
}

// fetch all nodes
nodes, err := getNodes(f.Context(), shootClient)
seedTarget := target.NewTarget(currentTarget.GardenName(), "", *shoot.Spec.SeedName, "")

seedClient, err := manager.SeedClient(ctx, seedTarget)
if err != nil {
return nil, err
}

// collect names, filter by prefix
nodeNames := []string{}
machines, err := getMachines(ctx, seedClient, shoot.Status.TechnicalID)
if err != nil {
return nil, err
}

for _, node := range nodes {
if strings.HasPrefix(node.Name, prefix) {
nodeNames = append(nodeNames, node.Name)
var nodeNames []string

for _, machine := range machines {
if _, ok := machine.Labels[machinev1alpha1.NodeLabelKey]; !ok {
continue
}

nodeNames = append(nodeNames, machine.Labels[machinev1alpha1.NodeLabelKey])
}

return nodeNames, nil
}

func getNodeNamesFromNodes(ctx context.Context, manager target.Manager, currentTarget target.Target) ([]string, error) {
shootClient, err := manager.ShootClient(ctx, currentTarget)
if err != nil {
return nil, err
}

nodes, err := getNodes(ctx, shootClient)
if err != nil {
return nil, err
}

var nodeNames []string
for _, node := range nodes {
nodeNames = append(nodeNames, node.Name)
}

return nodeNames, nil
Expand Down Expand Up @@ -1103,6 +1143,15 @@ func getNodes(ctx context.Context, c client.Client) ([]corev1.Node, error) {
return nodeList.Items, nil
}

func getMachines(ctx context.Context, c client.Client, namespace string) ([]machinev1alpha1.Machine, error) {
machineList := machinev1alpha1.MachineList{}
if err := c.List(ctx, &machineList, client.InNamespace(namespace)); err != nil {
return nil, fmt.Errorf("failed to list machines: %w", err)
}

return machineList.Items, nil
}

func (o *SSHOptions) checkAccessRestrictions(cfg *config.Config, gardenName string, tf target.TargetFlags, shoot *gardencorev1beta1.Shoot) (bool, error) {
if cfg == nil {
return false, errors.New("garden configuration is required")
Expand Down
19 changes: 17 additions & 2 deletions pkg/cmd/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0
package ssh

import (
"strings"

"github.com/spf13/cobra"
"k8s.io/klog/v2"

Expand Down Expand Up @@ -51,13 +53,26 @@ gardenctl ssh --keep-bastion --bastion-name cli-xxxxxxxx --public-key-file /path
return nil, cobra.ShellCompDirectiveNoFileComp
}

nodeNames, err := getNodeNamesFromShoot(f, toComplete)
manager, err := f.Manager()
if err != nil {
logger.Error(err, "could not get manager from factory")
return nil, cobra.ShellCompDirectiveNoFileComp
}

nodeNames, err := getNodeNamesFromMachinesOrNodes(ctx, manager)
if err != nil {
logger.Error(err, "could not get node names from shoot")
return nil, cobra.ShellCompDirectiveNoFileComp
}

return nodeNames, cobra.ShellCompDirectiveNoFileComp
var completions []string
for _, nodeName := range nodeNames {
if strings.HasPrefix(nodeName, toComplete) {
completions = append(completions, nodeName)
}
}

return completions, cobra.ShellCompDirectiveNoFileComp
},
RunE: base.WrapRunE(o, f),
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/cmd/ssh/ssh_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
operationsv1alpha1 "github.com/gardener/gardener/pkg/apis/operations/v1alpha1"
machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
"github.com/google/uuid"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand All @@ -23,6 +24,7 @@ import (
func init() {
utilruntime.Must(gardencorev1beta1.AddToScheme(scheme.Scheme))
utilruntime.Must(operationsv1alpha1.AddToScheme(scheme.Scheme))
utilruntime.Must(machinev1alpha1.AddToScheme(scheme.Scheme))
}

func TestCommand(t *testing.T) {
Expand Down
Loading

0 comments on commit a7b2f85

Please sign in to comment.