@@ -16,15 +16,28 @@ package instance
16
16
import (
17
17
"context"
18
18
"errors"
19
+ "fmt"
20
+ "time"
19
21
20
22
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
23
+ ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
21
24
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
25
+ "github.com/aws/aws-sdk-go-v2/aws"
22
26
svcsdk "github.com/aws/aws-sdk-go-v2/service/ec2"
23
27
svcsdktypes "github.com/aws/aws-sdk-go-v2/service/ec2/types"
24
28
29
+ "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1"
25
30
"github.com/aws-controllers-k8s/ec2-controller/pkg/tags"
26
31
)
27
32
33
+ const (
34
+ stateRunning = "running"
35
+ stateStopped = "stopped"
36
+ stateTerminated = "terminated"
37
+
38
+ requeueUntilReadyDuration = 10 * time .Second
39
+ )
40
+
28
41
// addInstanceIDsToTerminateRequest populates the list of InstanceIDs
29
42
// in the TerminateInstances request with the resource's InstanceID
30
43
// Return error to indicate to callers that the resource is not yet created.
@@ -53,19 +66,126 @@ func (rm *resourceManager) customUpdateInstance(
53
66
// an error, then the update was successful and desired.Spec
54
67
// (now updated.Spec) reflects the latest resource state.
55
68
updated = rm .concreteResource (desired .DeepCopy ())
69
+ updated .SetStatus (latest )
56
70
57
71
if delta .DifferentAt ("Spec.Tags" ) {
58
72
if err := tags .Sync (
59
73
ctx , rm .sdkapi , rm .metrics , * latest .ko .Status .InstanceID ,
60
74
desired .ko .Spec .Tags , latest .ko .Spec .Tags ,
61
75
); err != nil {
62
- return nil , err
76
+ return updated , err
63
77
}
64
78
}
65
79
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
+
66
96
return updated , nil
67
97
}
68
98
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
+
69
189
var computeTagsDelta = tags .ComputeTagsDelta
70
190
71
191
// updateTagSpecificationsInCreateRequest adds
0 commit comments