@@ -16,15 +16,28 @@ package instance
1616import (
1717 "context"
1818 "errors"
19+ "fmt"
20+ "time"
1921
2022 ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
23+ ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
2124 ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
25+ "github.com/aws/aws-sdk-go-v2/aws"
2226 svcsdk "github.com/aws/aws-sdk-go-v2/service/ec2"
2327 svcsdktypes "github.com/aws/aws-sdk-go-v2/service/ec2/types"
2428
29+ "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1"
2530 "github.com/aws-controllers-k8s/ec2-controller/pkg/tags"
2631)
2732
33+ const (
34+ stateRunning = "running"
35+ stateStopped = "stopped"
36+ stateTerminated = "terminated"
37+
38+ requeueUntilReadyDuration = 10 * time .Second
39+ )
40+
2841// addInstanceIDsToTerminateRequest populates the list of InstanceIDs
2942// in the TerminateInstances request with the resource's InstanceID
3043// Return error to indicate to callers that the resource is not yet created.
@@ -53,19 +66,126 @@ func (rm *resourceManager) customUpdateInstance(
5366 // an error, then the update was successful and desired.Spec
5467 // (now updated.Spec) reflects the latest resource state.
5568 updated = rm .concreteResource (desired .DeepCopy ())
69+ updated .SetStatus (latest )
5670
5771 if delta .DifferentAt ("Spec.Tags" ) {
5872 if err := tags .Sync (
5973 ctx , rm .sdkapi , rm .metrics , * latest .ko .Status .InstanceID ,
6074 desired .ko .Spec .Tags , latest .ko .Spec .Tags ,
6175 ); err != nil {
62- return nil , err
76+ return updated , err
6377 }
6478 }
6579
80+ if ! delta .DifferentExcept ("Spec.Tags" ) {
81+ return updated , nil
82+ }
83+
84+ if ! isRunning (updated .ko ) {
85+ return updated , ackrequeue .NeededAfter (
86+ fmt .Errorf ("requeuing until state is %s or %s" , stateRunning , stateStopped ),
87+ requeueUntilReadyDuration ,
88+ )
89+ }
90+
91+ err = rm .modifyInstanceAttributes (ctx , delta , desired , latest )
92+ if err != nil {
93+ return updated , err
94+ }
95+
6696 return updated , nil
6797}
6898
99+ func (rm * resourceManager ) modifyInstanceAttributes (ctx context.Context , delta * ackcompare.Delta , desired , latest * resource ) (err error ) {
100+ rlog := ackrtlog .FromContext (ctx )
101+ exit := rlog .Trace ("rm.modifyInstanceAttributes" )
102+ defer exit (err )
103+ input := & svcsdk.ModifyInstanceAttributeInput {
104+ InstanceId : latest .ko .Status .InstanceID ,
105+ }
106+ if delta .DifferentAt ("Spec.DisableAPITermination" ) {
107+ input .Attribute = "disableApiTermination"
108+ input .DisableApiTermination = & svcsdktypes.AttributeBooleanValue {Value : desired .ko .Spec .DisableAPITermination }
109+ } else if delta .DifferentAt ("Spec.InstanceType" ) {
110+ input .Attribute = "instanceType"
111+ input .InstanceType = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .InstanceType }
112+ } else if delta .DifferentAt ("Spec.KernelID" ) {
113+ input .Attribute = "kernel"
114+ input .Kernel = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .KernelID }
115+ } else if delta .DifferentAt ("Spec.RAMDiskID" ) {
116+ input .Attribute = "ramdisk"
117+ input .Ramdisk = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .RAMDiskID }
118+ } else if delta .DifferentAt ("Spec.InstanceInitiatedShutdownBehavior" ) {
119+ input .Attribute = "instanceInitiatedShutdownBehavior"
120+ input .InstanceInitiatedShutdownBehavior = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .InstanceInitiatedShutdownBehavior }
121+ } else if delta .DifferentAt ("Spec.UserData" ) {
122+ input .Attribute = "userData"
123+ input .UserData = & svcsdktypes.BlobAttributeValue {Value : []byte (stringOrEmpty (desired .ko .Spec .UserData ))}
124+ } else if delta .DifferentAt ("Spec.EBSOptimized" ) {
125+ input .Attribute = "ebsOptimized"
126+ input .EbsOptimized = & svcsdktypes.AttributeBooleanValue {Value : desired .ko .Spec .EBSOptimized }
127+ } else if delta .DifferentAt ("Spec.DisableAPIStop" ) {
128+ input .Attribute = "disableApiStop"
129+ input .DisableApiStop = & svcsdktypes.AttributeBooleanValue {Value : desired .ko .Spec .DisableAPIStop }
130+ } else if delta .DifferentAt ("Spec.SecurityGroupIDs" ) {
131+ input .Attribute = "groupSet"
132+ input .Groups = aws .ToStringSlice (desired .ko .Spec .SecurityGroupIDs )
133+ }
134+
135+ if input .Attribute != "" {
136+ _ , err := rm .sdkapi .ModifyInstanceAttribute (ctx , input )
137+ rm .metrics .RecordAPICall ("UPDATE" , "ModifyInstanceAttribute" , err )
138+ if err != nil {
139+ return err
140+ }
141+ return fmt .Errorf ("requeuing until all fields are updated" )
142+ }
143+ return nil
144+ }
145+
146+ func isRunning (ko * v1alpha1.Instance ) bool {
147+ if ko .Status .State == nil || ko .Status .State .Name == nil {
148+ return false
149+ }
150+
151+ // NOTE: (michaelhtm) We will count `stopped` as running for now.
152+ // TODO: expose annotation to allow users to start/stop instances
153+ return * ko .Status .State .Name == stateRunning || * ko .Status .State .Name == stateStopped
154+ }
155+
156+ func needsRestart (ko * v1alpha1.Instance ) bool {
157+ if ko .Status .State == nil || ko .Status .State .Name == nil {
158+ return false
159+ }
160+
161+ return * ko .Status .State .Name == stateTerminated
162+ }
163+
164+ func stringOrEmpty (s * string ) string {
165+ if s == nil {
166+ return ""
167+ }
168+
169+ return * s
170+ }
171+
172+ func setAdditionalFields (instance svcsdktypes.Instance , ko * v1alpha1.Instance ) {
173+ ko .Spec .SecurityGroupIDs = []* string {}
174+ for _ , group := range instance .SecurityGroups {
175+ ko .Spec .SecurityGroupIDs = append (ko .Spec .SecurityGroupIDs , group .GroupId )
176+ }
177+
178+ if monitoring := instance .Monitoring ; monitoring != nil {
179+ switch monitoring .State {
180+ case svcsdktypes .MonitoringStateDisabled , svcsdktypes .MonitoringStateDisabling :
181+ ko .Spec .Monitoring = & v1alpha1.RunInstancesMonitoringEnabled {Enabled : aws .Bool (false )}
182+
183+ case svcsdktypes .MonitoringStateEnabled , svcsdktypes .MonitoringStatePending :
184+ ko .Spec .Monitoring = & v1alpha1.RunInstancesMonitoringEnabled {Enabled : aws .Bool (true )}
185+ }
186+ }
187+ }
188+
69189var computeTagsDelta = tags .ComputeTagsDelta
70190
71191// updateTagSpecificationsInCreateRequest adds
0 commit comments