Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
{{- with .Values.additionalAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
controller-gen.kubebuilder.io/version: v0.18.0
controller-gen.kubebuilder.io/version: v0.19.0
name: ec2nodeclasses.karpenter.k8s.aws
spec:
group: karpenter.k8s.aws
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/crds/karpenter.k8s.aws_ec2nodeclasses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.18.0
controller-gen.kubebuilder.io/version: v0.19.0
name: ec2nodeclasses.karpenter.k8s.aws
spec:
group: karpenter.k8s.aws
Expand Down
1 change: 1 addition & 0 deletions pkg/controllers/nodeclass/instanceprofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func (ip *InstanceProfile) Reconcile(ctx context.Context, nodeClass *v1.EC2NodeC
nodeClass.InstanceProfileRole(),
nodeClass.InstanceProfileTags(options.FromContext(ctx).ClusterName, ip.region),
string(nodeClass.UID),
true,
); err != nil {
// If we failed Create, we may have successfully created the instance profile but failed to either attach the new
// role or remove the existing role. To prevent runaway instance profile creation, we'll attempt to delete the
Expand Down
20 changes: 15 additions & 5 deletions pkg/providers/instanceprofile/instanceprofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import (

type Provider interface {
Get(context.Context, string) (*iamtypes.InstanceProfile, error)
Create(context.Context, string, string, map[string]string, string) error
Create(context.Context, string, string, map[string]string, string, bool) error
Delete(context.Context, string) error
ListClusterProfiles(context.Context) ([]*iamtypes.InstanceProfile, error)
ListNodeClassProfiles(context.Context, *v1.EC2NodeClass) ([]*iamtypes.InstanceProfile, error)
Expand Down Expand Up @@ -87,7 +87,14 @@ func (p *DefaultProvider) Get(ctx context.Context, instanceProfileName string) (
return out.InstanceProfile, nil
}

func (p *DefaultProvider) Create(ctx context.Context, instanceProfileName string, roleName string, tags map[string]string, nodeClassUID string) error {
func (p *DefaultProvider) Create(
ctx context.Context,
instanceProfileName string,
roleName string,
tags map[string]string,
nodeClassUID string,
usePath bool,
) error {
// Don't attempt to create an instance profile if the role hasn't been found. This prevents runaway instance profile
// creation by the NodeClass controller when there's a missing role.
if err, ok := p.roleNotFoundErrorCache.HasError(roleName); ok {
Expand All @@ -100,11 +107,14 @@ func (p *DefaultProvider) Create(ctx context.Context, instanceProfileName string
if !awserrors.IsNotFound(err) {
return serrors.Wrap(fmt.Errorf("getting instance profile, %w", err), "instance-profile", instanceProfileName)
}
o, err := p.iamapi.CreateInstanceProfile(ctx, &iam.CreateInstanceProfileInput{
input := &iam.CreateInstanceProfileInput{
InstanceProfileName: lo.ToPtr(instanceProfileName),
Tags: utils.IAMMergeTags(tags),
Path: lo.ToPtr(fmt.Sprintf("/karpenter/%s/%s/%s/", p.region, options.FromContext(ctx).ClusterName, nodeClassUID)),
})
}
if usePath {
input.Path = lo.ToPtr(fmt.Sprintf("/karpenter/%s/%s/%s/", p.region, options.FromContext(ctx).ClusterName, nodeClassUID))
}
o, err := p.iamapi.CreateInstanceProfile(ctx, input)
if err != nil {
return serrors.Wrap(err, "instance-profile", instanceProfileName)
}
Expand Down
14 changes: 7 additions & 7 deletions pkg/providers/instanceprofile/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ var _ = Describe("InstanceProfileProvider", func() {
func(roleWithPath, role string) {
const profileName = "profile-A"
nodeClass.Spec.Role = roleWithPath
Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, role, nil, string(nodeClass.UID))).To(Succeed())
Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, role, nil, string(nodeClass.UID), true)).To(Succeed())
Expect(profileName).ToNot(BeNil())
Expect(awsEnv.IAMAPI.InstanceProfiles[profileName].Roles).To(HaveLen(1))
Expect(aws.ToString(awsEnv.IAMAPI.InstanceProfiles[profileName].Roles[0].RoleName)).To(Equal(role))
Expand Down Expand Up @@ -269,7 +269,7 @@ var _ = Describe("InstanceProfileProvider", func() {
nodeClassUID := "test-uid"
expectedPath := fmt.Sprintf("/karpenter/%s/%s/%s/", fake.DefaultRegion, options.FromContext(ctx).ClusterName, nodeClassUID)

Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, nodeRole, nil, nodeClassUID)).To(Succeed())
Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, nodeRole, nil, nodeClassUID, true)).To(Succeed())

// Get the created profile
profile, err := awsEnv.InstanceProfileProvider.Get(ctx, profileName)
Expand All @@ -287,7 +287,7 @@ var _ = Describe("InstanceProfileProvider", func() {
profileName := "profile-A"
nodeClassUID := "test-uid"

Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, nodeRole, nil, nodeClassUID)).To(Succeed())
Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, nodeRole, nil, nodeClassUID, true)).To(Succeed())

// Verify profile exists
Expect(awsEnv.IAMAPI.InstanceProfiles).To(HaveKey(profileName))
Expand All @@ -308,7 +308,7 @@ var _ = Describe("InstanceProfileProvider", func() {
It("should reflect IsProtected updates", func() {
// Create a profile
profileName := "profile-A"
Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, nodeRole, nil, "test-uid")).To(Succeed())
Expect(awsEnv.InstanceProfileProvider.Create(ctx, profileName, nodeRole, nil, "test-uid", true)).To(Succeed())

// Initially should not be protected (protection is set in instance profile reconciler)
Expect(awsEnv.InstanceProfileProvider.IsProtected(profileName)).To(BeFalse())
Expand All @@ -331,14 +331,14 @@ var _ = Describe("InstanceProfileProvider", func() {
}
})
It("should not cache role not found errors when the role exists", func() {
err := awsEnv.InstanceProfileProvider.Create(ctx, "test-profile", roleName, nil, "test-uid")
err := awsEnv.InstanceProfileProvider.Create(ctx, "test-profile", roleName, nil, "test-uid", true)
Expect(err).ToNot(HaveOccurred())
_, ok := awsEnv.RoleCache.Get(roleName)
Expect(ok).To(BeFalse())
})
It("should cache role not found errors when the role does not", func() {
missingRoleName := "non-existent-role"
err := awsEnv.InstanceProfileProvider.Create(ctx, "test-profile", missingRoleName, nil, "test-uid")
err := awsEnv.InstanceProfileProvider.Create(ctx, "test-profile", missingRoleName, nil, "test-uid", true)
Expect(err).To(HaveOccurred())
_, ok := awsEnv.RoleCache.Get(missingRoleName)
Expect(ok).To(BeTrue())
Expand All @@ -347,7 +347,7 @@ var _ = Describe("InstanceProfileProvider", func() {
missingRoleName := "non-existent-role"
awsEnv.RoleCache.SetDefault(missingRoleName, errors.New("role not found"))

err := awsEnv.InstanceProfileProvider.Create(ctx, "test-profile", missingRoleName, nil, "test-uid")
err := awsEnv.InstanceProfileProvider.Create(ctx, "test-profile", missingRoleName, nil, "test-uid", true)
Expect(err).To(HaveOccurred())

Expect(awsEnv.IAMAPI.InstanceProfiles).To(HaveLen(0))
Expand Down