Enable support for the ASG WarmPool lifecycle hook

Update pkg/model/iam/iam_builder.go

Co-authored-by: Ciprian Hacman <ciprianhacman@gmail.com>
This commit is contained in:
Ole Markus With 2021-04-18 19:47:14 +02:00
parent 4fa59e4e00
commit 1ec0bd18e8
62 changed files with 1411 additions and 19 deletions

View File

@ -906,6 +906,12 @@ spec:
description: WarmPool configures an ASG warm pool for the instance
group
properties:
enableLifecycleHook:
description: EnableLifecyleHook determines if an ASG lifecycle
hook will be added ensuring that nodeup runs to completion.
Note that the metadata API must be protected from arbitrary
Pods when this is enabled.
type: boolean
maxSize:
description: MaxSize is the maximum size of the warm pool. The
desired size of the instance group is subtracted from this number

View File

@ -194,6 +194,9 @@ type WarmPoolSpec struct {
// (unless the resulting number is smaller than MinSize).
// The default is the instance group's MaxSize.
MaxSize *int64 `json:"maxSize,omitempty"`
// EnableLifecyleHook determines if an ASG lifecycle hook will be added ensuring that nodeup runs to completion.
// Note that the metadata API must be protected from arbitrary Pods when this is enabled.
EnableLifecyleHook bool `json:"enableLifecycleHook,omitempty"`
}
const (

View File

@ -159,6 +159,9 @@ type WarmPoolSpec struct {
// (unless the resulting number is smaller than MinSize).
// The default is the instance group's MaxSize.
MaxSize *int64 `json:"maxSize,omitempty"`
// EnableLifecyleHook determines if an ASG lifecycle hook will be added ensuring that nodeup runs to completion.
// Note that the metadata API must be protected from arbitrary Pods when this is enabled.
EnableLifecyleHook bool `json:"enableLifecycleHook,omitempty"`
}
// InstanceMetadataOptions defines the EC2 instance metadata service options (AWS Only)

View File

@ -6411,6 +6411,7 @@ func Convert_kops_VolumeSpec_To_v1alpha2_VolumeSpec(in *kops.VolumeSpec, out *Vo
func autoConvert_v1alpha2_WarmPoolSpec_To_kops_WarmPoolSpec(in *WarmPoolSpec, out *kops.WarmPoolSpec, s conversion.Scope) error {
out.MinSize = in.MinSize
out.MaxSize = in.MaxSize
out.EnableLifecyleHook = in.EnableLifecyleHook
return nil
}
@ -6422,6 +6423,7 @@ func Convert_v1alpha2_WarmPoolSpec_To_kops_WarmPoolSpec(in *WarmPoolSpec, out *k
func autoConvert_kops_WarmPoolSpec_To_v1alpha2_WarmPoolSpec(in *kops.WarmPoolSpec, out *WarmPoolSpec, s conversion.Scope) error {
out.MinSize = in.MinSize
out.MaxSize = in.MaxSize
out.EnableLifecyleHook = in.EnableLifecyleHook
return nil
}

View File

@ -329,7 +329,7 @@ func (b *PolicyBuilder) AddOSSPermissions(p *Policy) (*Policy, error) {
}
}
nodeRole, err := iam.BuildNodeRoleSubject(b.Role)
nodeRole, err := iam.BuildNodeRoleSubject(b.Role, false)
if err != nil {
return nil, err
}

View File

@ -21,6 +21,7 @@ import (
"sort"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"k8s.io/klog/v2"
"k8s.io/kops/pkg/apis/kops"
@ -96,6 +97,26 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
if warmPool != nil {
warmPoolTask.MinSize = warmPool.MinSize
warmPoolTask.MaxSize = warmPool.MaxSize
if warmPool.EnableLifecyleHook {
name := "kops-warmpool"
lifecyleTask := &awstasks.AutoscalingLifecycleHook{
ID: aws.String(name),
Name: aws.String(name),
Lifecycle: b.Lifecycle,
AutoscalingGroup: b.LinkToAutoscalingGroup(ig),
DefaultResult: aws.String("ABANDON"),
// We let nodeup have 10 min to complete. Normally this should happen much faster,
// but CP nodes need 5 min or so to start on new clusters, and we need to wait for that.
HeartbeatTimeout: aws.Int64(600),
LifecycleTransition: aws.String("autoscaling:EC2_INSTANCE_LAUNCHING"),
}
c.AddTask(lifecyleTask)
}
}
c.AddTask(warmPoolTask)
}

View File

@ -100,7 +100,7 @@ func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.ModelBuilderC
},
}
nodeRole, err := iam.BuildNodeRoleSubject(ig.Spec.Role)
nodeRole, err := iam.BuildNodeRoleSubject(ig.Spec.Role, false)
if err != nil {
return nil, err
}

View File

@ -68,7 +68,7 @@ func (b *StorageAclBuilder) Build(c *fi.ModelBuilderContext) error {
}
klog.Warningf("we need to split master / node roles")
nodeRole, err := iam.BuildNodeRoleSubject(kops.InstanceGroupRoleMaster)
nodeRole, err := iam.BuildNodeRoleSubject(kops.InstanceGroupRoleMaster, false)
if err != nil {
return err
}

View File

@ -75,7 +75,15 @@ func (b *IAMModelBuilder) Build(c *fi.ModelBuilderContext) error {
// Generate IAM tasks for each shared role
for profileARN, igRole := range sharedProfileARNsToIGRole {
role, err := iam.BuildNodeRoleSubject(igRole)
lchPermissions := false
for _, ig := range b.InstanceGroups {
if ig.Spec.Role == igRole && ig.Spec.WarmPool != nil && ig.Spec.WarmPool.EnableLifecyleHook {
lchPermissions = true
break
}
}
role, err := iam.BuildNodeRoleSubject(igRole, lchPermissions)
if err != nil {
return err
}
@ -92,7 +100,15 @@ func (b *IAMModelBuilder) Build(c *fi.ModelBuilderContext) error {
// Generate IAM tasks for each managed role
for igRole := range managedRoles {
role, err := iam.BuildNodeRoleSubject(igRole)
warmPool := false
for _, ig := range b.InstanceGroups {
if ig.Spec.Role == igRole && ig.Spec.WarmPool != nil && ig.Spec.WarmPool.EnableLifecyleHook {
warmPool = true
break
}
}
role, err := iam.BuildNodeRoleSubject(igRole, warmPool)
if err != nil {
return err
}

View File

@ -245,7 +245,7 @@ func (r *NodeRoleAPIServer) BuildAWSPolicy(b *PolicyBuilder) (*Policy, error) {
}
addMasterEC2Policies(p, resource, b.Cluster.Spec.IAM.Legacy, b.Cluster.GetName())
addASLifecyclePolicies(p, resource, b.Cluster.GetName())
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), r.warmPool)
addCertIAMPolicies(p, resource)
var err error
@ -293,6 +293,7 @@ func (r *NodeRoleMaster) BuildAWSPolicy(b *PolicyBuilder) (*Policy, error) {
}
addMasterEC2Policies(p, resource, b.Cluster.Spec.IAM.Legacy, b.Cluster.GetName())
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), true)
addMasterASPolicies(p, resource, b.Cluster.Spec.IAM.Legacy, b.Cluster.GetName())
addMasterELBPolicies(p, resource, b.Cluster.Spec.IAM.Legacy)
addCertIAMPolicies(p, resource)
@ -354,7 +355,7 @@ func (r *NodeRoleNode) BuildAWSPolicy(b *PolicyBuilder) (*Policy, error) {
}
addNodeEC2Policies(p, resource)
addASLifecyclePolicies(p, resource, b.Cluster.GetName())
addASLifecyclePolicies(p, resource, b.Cluster.GetName(), r.enableLifecycleHookPermissions)
var err error
if p, err = b.AddS3Permissions(p); err != nil {
@ -1033,8 +1034,32 @@ func addMasterASPolicies(p *Policy, resource stringorslice.StringOrSlice, legacy
}
}
func addASLifecyclePolicies(p *Policy, resource stringorslice.StringOrSlice, clusterName string) {
func addASLifecyclePolicies(p *Policy, resource stringorslice.StringOrSlice, clusterName string, enableHookSupport bool) {
if enableHookSupport {
p.Statement = append(p.Statement,
&Statement{
Effect: StatementEffectAllow,
Action: stringorslice.Of(
"autoscaling:CompleteLifecycleAction", // aws_manager.go
),
Resource: resource,
Condition: Condition{
"StringEquals": map[string]string{
"autoscaling:ResourceTag/KubernetesCluster": clusterName,
},
},
},
&Statement{
Effect: StatementEffectAllow,
Action: stringorslice.Of(
"autoscaling:DescribeLifecycleHooks",
),
Resource: resource,
},
)
}
p.Statement = append(p.Statement,
&Statement{
Effect: StatementEffectAllow,
Action: stringorslice.Of(

View File

@ -51,6 +51,7 @@ func (_ *NodeRoleMaster) ServiceAccount() (types.NamespacedName, bool) {
// NodeRoleAPIServer represents the role of API server-only nodes, and implements Subject.
type NodeRoleAPIServer struct {
warmPool bool
}
// ServiceAccount implements Subject.
@ -60,6 +61,7 @@ func (_ *NodeRoleAPIServer) ServiceAccount() (types.NamespacedName, bool) {
// NodeRoleNode represents the role of normal ("worker") nodes, and implements Subject.
type NodeRoleNode struct {
enableLifecycleHookPermissions bool
}
// ServiceAccount implements Subject.
@ -77,14 +79,18 @@ func (_ *NodeRoleBastion) ServiceAccount() (types.NamespacedName, bool) {
}
// BuildNodeRoleSubject returns a Subject implementation for the specified InstanceGroupRole.
func BuildNodeRoleSubject(igRole kops.InstanceGroupRole) (Subject, error) {
func BuildNodeRoleSubject(igRole kops.InstanceGroupRole, enableLifecycleHookPermissions bool) (Subject, error) {
switch igRole {
case kops.InstanceGroupRoleMaster:
return &NodeRoleMaster{}, nil
case kops.InstanceGroupRoleAPIServer:
return &NodeRoleAPIServer{}, nil
return &NodeRoleAPIServer{
warmPool: enableLifecycleHookPermissions,
}, nil
case kops.InstanceGroupRoleNode:
return &NodeRoleNode{}, nil
return &NodeRoleNode{
enableLifecycleHookPermissions: enableLifecycleHookPermissions,
}, nil
case kops.InstanceGroupRoleBastion:
return &NodeRoleBastion{}, nil
default:

View File

@ -9,6 +9,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "iam-builder-test.k8s.local"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "iam-builder-test.k8s.local"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "iam-builder-test.k8s.local"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1244,6 +1244,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "bastionuserdata.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1619,6 +1619,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "complex.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "complex.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "compress.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -946,6 +946,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "containerd.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -946,6 +946,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "containerd.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -946,6 +946,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "docker.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "existingsg.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -962,6 +962,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "externallb.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "externallb.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "externalpolicies.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "ha.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -946,6 +946,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -942,6 +942,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal-json.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1649,6 +1649,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "mixedinstances.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "mixedinstances.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1650,6 +1650,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "mixedinstances.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "mixedinstances.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1056,6 +1056,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "nthsqsresources.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "nthsqsresources.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1441,6 +1441,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "private-shared-ip.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "private-shared-ip.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "private-shared-subnet.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1586,6 +1586,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecalico.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecalico.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecanal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1572,6 +1572,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecilium.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecilium.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1572,6 +1572,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecilium.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatecilium.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -1605,6 +1605,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privateciliumadvanced.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privateciliumadvanced.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatedns1.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatedns2.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privateflannel.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privatekopeio.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "privateweave.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "minimal.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "sharedsubnet.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "sharedvpc.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -51,6 +51,32 @@
"*"
]
},
{
"Action": "autoscaling:CompleteLifecycleAction",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/KubernetesCluster": "unmanaged.example.com"
}
},
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeLifecycleHooks",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": "autoscaling:DescribeAutoScalingInstances",
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",

View File

@ -95,14 +95,14 @@ func (_ *AutoscalingLifecycleHook) CheckChanges(a, e, changes *AutoscalingLifecy
return nil
}
func (h *AutoscalingLifecycleHook) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *AutoscalingLifecycleHook) error {
if a == nil {
func (*AutoscalingLifecycleHook) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *AutoscalingLifecycleHook) error {
if changes != nil {
request := &autoscaling.PutLifecycleHookInput{
AutoScalingGroupName: e.AutoscalingGroup.Name,
DefaultResult: h.DefaultResult,
HeartbeatTimeout: h.HeartbeatTimeout,
DefaultResult: e.DefaultResult,
HeartbeatTimeout: e.HeartbeatTimeout,
LifecycleHookName: e.Name,
LifecycleTransition: h.LifecycleTransition,
LifecycleTransition: e.LifecycleTransition,
}
_, err := t.Cloud.Autoscaling().PutLifecycleHook(request)
if err != nil {

View File

@ -205,12 +205,10 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
return err
}
awsCloud, err := awsup.NewAWSCloud(region, nil)
cloud = awsCloud
if err != nil {
return err
}
cloud = awsCloud
}
modelContext := &model.NodeupModelContext{
@ -363,6 +361,44 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
klog.Exitf("error closing target: %v", err)
}
if modelContext.InstanceGroup.Spec.WarmPool != nil && modelContext.InstanceGroup.Spec.WarmPool.EnableLifecyleHook {
if api.CloudProviderID(c.cluster.Spec.CloudProvider) == api.CloudProviderAWS {
err := completeWarmingLifecycleAction(cloud.(awsup.AWSCloud), modelContext)
if err != nil {
return fmt.Errorf("failed to complete lifecylce action: %w", err)
}
}
}
return nil
}
func completeWarmingLifecycleAction(cloud awsup.AWSCloud, modelContext *model.NodeupModelContext) error {
asgName := modelContext.InstanceGroup.GetName() + "." + modelContext.Cluster.GetName()
hookName := "kops-warmpool"
svc := cloud.(awsup.AWSCloud).Autoscaling()
hooks, err := svc.DescribeLifecycleHooks(&autoscaling.DescribeLifecycleHooksInput{
AutoScalingGroupName: &asgName,
LifecycleHookNames: []*string{&hookName},
})
if err != nil {
return fmt.Errorf("failed to find lifecycle hook %q: %w", hookName, err)
}
if len(hooks.LifecycleHooks) > 0 {
klog.Info("Found ASG lifecycle hook")
_, err := svc.CompleteLifecycleAction(&autoscaling.CompleteLifecycleActionInput{
AutoScalingGroupName: &asgName,
InstanceId: &modelContext.InstanceID,
LifecycleHookName: &hookName,
LifecycleActionResult: fi.String("CONTINUE"),
})
if err != nil {
return fmt.Errorf("failed to complete lifecycle hook %q for %q: %v", hookName, modelContext.InstanceID, err)
}
klog.Info("Lifecycle action completed")
} else {
klog.Info("No ASG lifecycle hook found")
}
return nil
}