@@ -17,7 +17,7 @@ import (
17
17
"k8s.io/client-go/dynamic"
18
18
"k8s.io/klog"
19
19
"k8s.io/kubectl/pkg/cmd/apply"
20
- "k8s.io/kubectl/pkg/cmd/delete"
20
+ cmddelete "k8s.io/kubectl/pkg/cmd/delete"
21
21
"k8s.io/kubectl/pkg/cmd/util"
22
22
"k8s.io/kubectl/pkg/util/slice"
23
23
applyerror "sigs.k8s.io/cli-utils/pkg/apply/error"
@@ -45,11 +45,13 @@ type applyOptions interface {
45
45
// ApplyTask applies the given Objects to the cluster
46
46
// by using the ApplyOptions.
47
47
type ApplyTask struct {
48
- Factory util.Factory
49
- InfoHelper info.InfoHelper
50
- Mapper meta.RESTMapper
51
- Objects []* unstructured.Unstructured
52
- CRDs []* unstructured.Unstructured
48
+ Factory util.Factory
49
+ InfoHelper info.InfoHelper
50
+ Mapper meta.RESTMapper
51
+ Objects []* unstructured.Unstructured
52
+ CRDs []* unstructured.Unstructured
53
+ // Used for determining inventory during errors
54
+ PrevInventory map [object.ObjMetadata ]bool
53
55
DryRunStrategy common.DryRunStrategy
54
56
ServerSideOptions common.ServerSideOptions
55
57
InventoryPolicy inventory.InventoryPolicy
@@ -80,6 +82,7 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
80
82
// we have a CRD and a CR in the same resource set, but the CRD
81
83
// will not actually have been applied when we reach the CR.
82
84
if a .DryRunStrategy .ClientOrServerDryRun () {
85
+ klog .V (4 ).Infof ("dry-run filtering custom resources..." )
83
86
// Find all resources in the set that doesn't exist in the
84
87
// RESTMapper, but where we do have the CRD for the type in
85
88
// the resource set.
@@ -97,6 +100,7 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
97
100
taskContext .EventChannel () <- createApplyEvent (object .UnstructuredToObjMeta (obj ), event .Created , nil )
98
101
}
99
102
// Update the resource set to no longer include the CRs.
103
+ klog .V (4 ).Infof ("after dry-run filtering custom resources, %d objects left" , len (objs ))
100
104
objects = objs
101
105
}
102
106
@@ -123,7 +127,8 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
123
127
}
124
128
125
129
klog .V (4 ).Infof ("attempting to apply %d remaining objects" , len (objects ))
126
- var infos []* resource.Info
130
+ // invInfos stores the objects which should be stored in the final inventory.
131
+ invInfos := make (map [object.ObjMetadata ]* resource.Info , len (objects ))
127
132
for _ , obj := range objects {
128
133
// Set the client and mapping fields on the provided
129
134
// info so they can be applied to the cluster.
@@ -144,18 +149,25 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
144
149
if err != nil {
145
150
if ! apierrors .IsNotFound (err ) {
146
151
if klog .V (4 ) {
147
- klog .Errorf ("error retrieving %s/%s from cluster--continue" ,
152
+ klog .Errorf ("error (%s) retrieving %s/%s from cluster--continue" ,
153
+ err , info .Namespace , info .Name )
154
+ }
155
+ op := event .Failed
156
+ if a .objInCluster (id ) {
157
+ // Object in cluster stays in the inventory.
158
+ klog .V (4 ).Infof ("%s/%s apply retrieval failure, but in cluster--keep in inventory" ,
148
159
info .Namespace , info .Name )
160
+ invInfos [id ] = info
161
+ op = event .Unchanged
149
162
}
150
- taskContext .EventChannel () <- createApplyEvent (
151
- id ,
152
- event .Unchanged ,
153
- err )
163
+ taskContext .EventChannel () <- createApplyEvent (id , op , err )
154
164
taskContext .CaptureResourceFailure (id )
155
165
continue
156
166
}
157
167
}
158
- infos = append (infos , info )
168
+ // At this point the object was either 1) successfully retrieved from the cluster, or
169
+ // 2) returned "Not Found" error (meaning first-time creation). Add to final inventory.
170
+ invInfos [id ] = info
159
171
canApply , err := inventory .CanApply (a .InvInfo , clusterObj , a .InventoryPolicy )
160
172
if ! canApply {
161
173
klog .V (5 ).Infof ("can not apply %s/%s--continue" ,
@@ -176,30 +188,30 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
176
188
if klog .V (4 ) {
177
189
klog .Errorf ("error applying (%s/%s) %s" , info .Namespace , info .Name , err )
178
190
}
191
+ // If apply failed and the object is not in the cluster, remove
192
+ // it from the final inventory.
193
+ if ! a .objInCluster (id ) {
194
+ klog .V (5 ).Infof ("not in cluster; removing apply fail object %s/%s from inventory" ,
195
+ info .Namespace , info .Name )
196
+ delete (invInfos , id )
197
+ }
179
198
taskContext .EventChannel () <- createApplyEvent (
180
199
id , event .Failed , applyerror .NewApplyRunError (err ))
181
200
taskContext .CaptureResourceFailure (id )
182
201
}
183
202
}
184
203
185
- // Fetch the Generation from all Infos after they have been
186
- // applied.
187
- for _ , inf := range infos {
188
- id , err := object .InfoToObjMeta (inf )
189
- if err != nil {
190
- continue
191
- }
192
- if inf .Object != nil {
193
- acc , err := meta .Accessor (inf .Object )
204
+ // Store objects (and some obj metadata) in the task context
205
+ // for the final inventory.
206
+ for id , info := range invInfos {
207
+ if info .Object != nil {
208
+ acc , err := meta .Accessor (info .Object )
194
209
if err != nil {
195
210
continue
196
211
}
197
- // Only add a resource if it successfully applied.
198
212
uid := acc .GetUID ()
199
- if string (uid ) != "" {
200
- gen := acc .GetGeneration ()
201
- taskContext .ResourceApplied (id , uid , gen )
202
- }
213
+ gen := acc .GetGeneration ()
214
+ taskContext .ResourceApplied (id , uid , gen )
203
215
}
204
216
}
205
217
a .sendTaskResult (taskContext )
@@ -232,7 +244,7 @@ func newApplyOptions(eventChannel chan event.Event, serverSideOptions common.Ser
232
244
},
233
245
// FilenameOptions are not needed since we don't use the ApplyOptions
234
246
// to read manifests.
235
- DeleteOptions : & delete .DeleteOptions {},
247
+ DeleteOptions : & cmddelete .DeleteOptions {},
236
248
PrintFlags : & genericclioptions.PrintFlags {
237
249
OutputFormat : & emptyString ,
238
250
},
@@ -292,6 +304,16 @@ func (a *ApplyTask) filterCRsWithCRDInSet(objects []*unstructured.Unstructured)
292
304
return objs , objsWithCRD , nil
293
305
}
294
306
307
+ // objInCluster returns true if the passed object is in the slice of
308
+ // previous inventory, because an object in the previous inventory
309
+ // exists in the cluster.
310
+ func (a * ApplyTask ) objInCluster (obj object.ObjMetadata ) bool {
311
+ if _ , found := a .PrevInventory [obj ]; found {
312
+ return true
313
+ }
314
+ return false
315
+ }
316
+
295
317
type crdsInfo struct {
296
318
crds []crdInfo
297
319
}
0 commit comments