@@ -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,115 @@ 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
77
+ }
78
+ }
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
+ input := & svcsdk.ModifyInstanceAttributeInput {
92
+ InstanceId : latest .ko .Status .InstanceID ,
93
+ }
94
+ if delta .DifferentAt ("Spec.DisableAPITermination" ) {
95
+ input .Attribute = "disableApiTermination"
96
+ input .DisableApiTermination = & svcsdktypes.AttributeBooleanValue {Value : desired .ko .Spec .DisableAPITermination }
97
+ } else if delta .DifferentAt ("Spec.InstanceType" ) {
98
+ input .Attribute = "instanceType"
99
+ input .InstanceType = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .InstanceType }
100
+ } else if delta .DifferentAt ("Spec.KernelID" ) {
101
+ input .Attribute = "kernel"
102
+ input .Kernel = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .KernelID }
103
+ } else if delta .DifferentAt ("Spec.RAMDiskID" ) {
104
+ input .Attribute = "ramdisk"
105
+ input .Ramdisk = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .RAMDiskID }
106
+ } else if delta .DifferentAt ("Spec.InstanceInitiatedShutdownBehavior" ) {
107
+ input .Attribute = "instanceInitiatedShutdownBehavior"
108
+ input .InstanceInitiatedShutdownBehavior = & svcsdktypes.AttributeValue {Value : desired .ko .Spec .InstanceInitiatedShutdownBehavior }
109
+ } else if delta .DifferentAt ("Spec.UserData" ) {
110
+ input .Attribute = "userData"
111
+ input .UserData = & svcsdktypes.BlobAttributeValue {Value : []byte (stringOrEmpty (desired .ko .Spec .UserData ))}
112
+ } else if delta .DifferentAt ("Spec.EBSOptimized" ) {
113
+ input .Attribute = "ebsOptimized"
114
+ input .EbsOptimized = & svcsdktypes.AttributeBooleanValue {Value : desired .ko .Spec .EBSOptimized }
115
+ } else if delta .DifferentAt ("Spec.DisableAPIStop" ) {
116
+ input .Attribute = "disableApiStop"
117
+ input .DisableApiStop = & svcsdktypes.AttributeBooleanValue {Value : desired .ko .Spec .DisableAPIStop }
118
+ } else if delta .DifferentAt ("Spec.SecurityGroupIDs" ) {
119
+ input .Attribute = "groupSet"
120
+ input .Groups = aws .ToStringSlice (desired .ko .Spec .SecurityGroupIDs )
121
+ }
122
+
123
+ if input .Attribute != "" {
124
+ _ , err := rm .sdkapi .ModifyInstanceAttribute (ctx , input )
125
+ rm .metrics .RecordAPICall ("UPDATE" , "ModifyInstanceAttribute" , err )
126
+ if err != nil {
127
+ return updated , err
63
128
}
129
+ return updated , fmt .Errorf ("requeuing until all fields are updated" )
64
130
}
65
131
66
132
return updated , nil
67
133
}
68
134
135
+ func isRunning (ko * v1alpha1.Instance ) bool {
136
+ if ko .Status .State == nil || ko .Status .State .Name == nil {
137
+ return false
138
+ }
139
+
140
+ // NOTE: (michaelhtm) We will count `stopped` as running for now.
141
+ // TODO: expose annotation to allow users to start/stop instances
142
+ return * ko .Status .State .Name == stateRunning || * ko .Status .State .Name == stateStopped
143
+ }
144
+
145
+ func needsRestart (ko * v1alpha1.Instance ) bool {
146
+ if ko .Status .State == nil || ko .Status .State .Name == nil {
147
+ return false
148
+ }
149
+
150
+ return * ko .Status .State .Name == stateTerminated
151
+ }
152
+
153
+ func stringOrEmpty (s * string ) string {
154
+ if s == nil {
155
+ return ""
156
+ }
157
+
158
+ return * s
159
+ }
160
+
161
+ func setAdditionalFields (instance svcsdktypes.Instance , ko * v1alpha1.Instance ) {
162
+ ko .Spec .SecurityGroupIDs = []* string {}
163
+ for _ , group := range instance .SecurityGroups {
164
+ ko .Spec .SecurityGroupIDs = append (ko .Spec .SecurityGroupIDs , group .GroupId )
165
+ }
166
+
167
+ if monitoring := instance .Monitoring ; monitoring != nil {
168
+ switch monitoring .State {
169
+ case svcsdktypes .MonitoringStateDisabled , svcsdktypes .MonitoringStateDisabling :
170
+ ko .Spec .Monitoring = & v1alpha1.RunInstancesMonitoringEnabled {Enabled : aws .Bool (false )}
171
+
172
+ case svcsdktypes .MonitoringStateEnabled , svcsdktypes .MonitoringStatePending :
173
+ ko .Spec .Monitoring = & v1alpha1.RunInstancesMonitoringEnabled {Enabled : aws .Bool (true )}
174
+ }
175
+ }
176
+ }
177
+
69
178
var computeTagsDelta = tags .ComputeTagsDelta
70
179
71
180
// updateTagSpecificationsInCreateRequest adds
0 commit comments