Skip to content

Commit a577ddc

Browse files
authored
Add EKS auto-mode pre-flight check to kubectl plugin install command (#2717)
Detect EKS auto-mode by checking for the nodeclasses CRD in the eks.amazonaws.com API group before installing Karpenter. When auto-mode is active, Karpenter is already built-in and does not need a separate installation — display a message directing the user to the Datadog autoscaling settings page instead.
1 parent a2fb04f commit a577ddc

3 files changed

Lines changed: 115 additions & 2 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package guess
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/samber/lo"
7+
apierrors "k8s.io/apimachinery/pkg/api/errors"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/client-go/discovery"
10+
)
11+
12+
// IsEKSAutoModeEnabled checks if EKS auto-mode is active on the cluster
13+
// by looking for the nodeclasses resource in the eks.amazonaws.com/v1 API group.
14+
func IsEKSAutoModeEnabled(discoveryClient discovery.DiscoveryInterface) (bool, error) {
15+
resources, err := discoveryClient.ServerResourcesForGroupVersion("eks.amazonaws.com/v1")
16+
if err != nil {
17+
if apierrors.IsNotFound(err) {
18+
return false, nil
19+
}
20+
return false, fmt.Errorf("failed to query eks.amazonaws.com/v1 API group: %w", err)
21+
}
22+
23+
return lo.ContainsBy(resources.APIResources, func(r metav1.APIResource) bool {
24+
return r.Name == "nodeclasses"
25+
}), nil
26+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package guess
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
fakediscovery "k8s.io/client-go/discovery/fake"
9+
k8stesting "k8s.io/client-go/testing"
10+
)
11+
12+
func TestIsEKSAutoModeEnabled(t *testing.T) {
13+
for _, tc := range []struct {
14+
name string
15+
resources []*metav1.APIResourceList
16+
expected bool
17+
}{
18+
{
19+
name: "EKS auto-mode is active",
20+
resources: []*metav1.APIResourceList{
21+
{
22+
GroupVersion: "eks.amazonaws.com/v1",
23+
APIResources: []metav1.APIResource{
24+
{Name: "nodeclasses", Kind: "NodeClass"},
25+
},
26+
},
27+
},
28+
expected: true,
29+
},
30+
{
31+
name: "EKS auto-mode is not active (group not found)",
32+
resources: []*metav1.APIResourceList{},
33+
expected: false,
34+
},
35+
{
36+
name: "EKS auto-mode is not active (group exists but no nodeclasses)",
37+
resources: []*metav1.APIResourceList{
38+
{
39+
GroupVersion: "eks.amazonaws.com/v1",
40+
APIResources: []metav1.APIResource{
41+
{Name: "nodeconfigs", Kind: "NodeConfig"},
42+
},
43+
},
44+
},
45+
expected: false,
46+
},
47+
} {
48+
t.Run(tc.name, func(t *testing.T) {
49+
fakeDiscovery := &fakediscovery.FakeDiscovery{
50+
Fake: &k8stesting.Fake{
51+
Resources: tc.resources,
52+
},
53+
}
54+
55+
result, err := IsEKSAutoModeEnabled(fakeDiscovery)
56+
assert.NoError(t, err)
57+
assert.Equal(t, tc.expected, result)
58+
})
59+
}
60+
}

cmd/kubectl-datadog/autoscaling/cluster/install/install.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ func (o *options) run(cmd *cobra.Command) error {
218218
}
219219
}
220220

221+
if autoModeEnabled, err := guess.IsEKSAutoModeEnabled(o.DiscoveryClient); err != nil {
222+
return fmt.Errorf("failed to check for EKS auto-mode: %w", err)
223+
} else if autoModeEnabled {
224+
return displayEKSAutoModeMessage(cmd, clusterName)
225+
}
226+
221227
display.PrintBox(cmd.OutOrStdout(), "Installing Karpenter on cluster "+clusterName+".")
222228

223229
cli, err := clients.Build(ctx, o.ConfigFlags, o.Clientset)
@@ -395,7 +401,7 @@ func createNodePoolResources(ctx context.Context, cmd *cobra.Command, cli *clien
395401
return nil
396402
}
397403

398-
func displaySuccessMessage(cmd *cobra.Command, clusterName string, createResources CreateKarpenterResources) error {
404+
func openAutoscalingSettingsURL(cmd *cobra.Command, clusterName string) string {
399405
autoscalingSettingsURL := (&url.URL{
400406
Scheme: "https",
401407
Host: "app.datadoghq.com",
@@ -409,7 +415,28 @@ func displaySuccessMessage(cmd *cobra.Command, clusterName string, createResourc
409415
log.Printf("Failed to open URL in browser: %v", err)
410416
}
411417

412-
coloredURL := color.New(color.Bold, color.Underline, color.FgBlue).Sprint(autoscalingSettingsURL)
418+
return color.New(color.Bold, color.Underline, color.FgBlue).Sprint(autoscalingSettingsURL)
419+
}
420+
421+
func displayEKSAutoModeMessage(cmd *cobra.Command, clusterName string) error {
422+
coloredURL := openAutoscalingSettingsURL(cmd, clusterName)
423+
424+
display.PrintBox(cmd.OutOrStdout(),
425+
"EKS auto-mode is already active on cluster "+clusterName+".",
426+
"",
427+
"Karpenter is built into EKS auto-mode",
428+
"and does not need to be installed separately.",
429+
"",
430+
"Navigate to the Autoscaling settings page",
431+
"and select cluster to start generating recommendations:",
432+
coloredURL,
433+
)
434+
435+
return nil
436+
}
437+
438+
func displaySuccessMessage(cmd *cobra.Command, clusterName string, createResources CreateKarpenterResources) error {
439+
coloredURL := openAutoscalingSettingsURL(cmd, clusterName)
413440

414441
switch createResources {
415442
case CreateKarpenterResourcesNone:

0 commit comments

Comments
 (0)