Skip to content

Commit b023543

Browse files
authored
Merge pull request #286 from Liujingfang1/apply
change apply to continue on error
2 parents 12fe2d5 + e808334 commit b023543

File tree

8 files changed

+294
-72
lines changed

8 files changed

+294
-72
lines changed

pkg/apply/applier_test.go

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -708,43 +708,35 @@ type fakeInfoHelper struct {
708708
// TODO(mortent): This has too much code in common with the
709709
// infoHelper implementation. We need to find a better way to structure
710710
// this.
711-
func (f *fakeInfoHelper) UpdateInfos(infos []*resource.Info) error {
711+
func (f *fakeInfoHelper) UpdateInfo(info *resource.Info) error {
712712
mapper, err := f.factory.ToRESTMapper()
713713
if err != nil {
714714
return err
715715
}
716-
for _, info := range infos {
717-
gvk := info.Object.GetObjectKind().GroupVersionKind()
718-
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
719-
if err != nil {
720-
return err
721-
}
722-
info.Mapping = mapping
716+
gvk := info.Object.GetObjectKind().GroupVersionKind()
717+
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
718+
if err != nil {
719+
return err
720+
}
721+
info.Mapping = mapping
723722

724-
c, err := f.getClient(gvk.GroupVersion())
725-
if err != nil {
726-
return err
727-
}
728-
info.Client = c
723+
c, err := f.getClient(gvk.GroupVersion())
724+
if err != nil {
725+
return err
729726
}
727+
info.Client = c
730728
return nil
731729
}
732730

733-
func (f *fakeInfoHelper) BuildInfos(objs []*unstructured.Unstructured) ([]*resource.Info, error) {
734-
var infos []*resource.Info
735-
for _, obj := range objs {
736-
infos = append(infos, &resource.Info{
737-
Name: obj.GetName(),
738-
Namespace: obj.GetNamespace(),
739-
Source: "unstructured",
740-
Object: obj,
741-
})
742-
}
743-
err := f.UpdateInfos(infos)
744-
if err != nil {
745-
return nil, err
731+
func (f *fakeInfoHelper) BuildInfo(obj *unstructured.Unstructured) (*resource.Info, error) {
732+
info := &resource.Info{
733+
Name: obj.GetName(),
734+
Namespace: obj.GetNamespace(),
735+
Source: "unstructured",
736+
Object: obj,
746737
}
747-
return infos, nil
738+
err := f.UpdateInfo(info)
739+
return info, err
748740
}
749741

750742
func (f *fakeInfoHelper) getClient(gv schema.GroupVersion) (resource.RESTClient, error) {

pkg/apply/error/error.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2019 The Kubernetes Authors.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package error
4+
5+
type UnknownTypeError struct {
6+
err error
7+
}
8+
9+
func (e *UnknownTypeError) Error() string {
10+
return e.err.Error()
11+
}
12+
13+
func NewUnknownTypeError(err error) *UnknownTypeError {
14+
return &UnknownTypeError{err: err}
15+
}
16+
17+
type ApplyRunError struct {
18+
err error
19+
}
20+
21+
func (e *ApplyRunError) Error() string {
22+
return e.err.Error()
23+
}
24+
25+
func NewApplyRunError(err error) *ApplyRunError {
26+
return &ApplyRunError{err: err}
27+
}
28+
29+
type InitializeApplyOptionError struct {
30+
err error
31+
}
32+
33+
func (e *InitializeApplyOptionError) Error() string {
34+
return e.err.Error()
35+
}
36+
37+
func NewInitializeApplyOptionError(err error) *InitializeApplyOptionError {
38+
return &InitializeApplyOptionError{err: err}
39+
}

pkg/apply/event/applyeventtype_string.go

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apply/event/event.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ type ApplyEventType int
8181
const (
8282
ApplyEventResourceUpdate ApplyEventType = iota
8383
ApplyEventCompleted
84-
ApplyEventFailed
8584
)
8685

8786
//go:generate stringer -type=ApplyEventOperation

pkg/apply/info/info_helper.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import (
1515

1616
// InfoHelper provides functions for interacting with Info objects.
1717
type InfoHelper interface {
18-
// UpdateInfos sets the mapping and client for the provided Info
19-
// objects. This must be called at a time when all needed resource
18+
// UpdateInfo sets the mapping and client for the provided Info
19+
// object. This must be called at a time when all needed resource
2020
// types are available in the RESTMapper.
21-
UpdateInfos(infos []*resource.Info) error
21+
UpdateInfo(info *resource.Info) error
2222

23-
BuildInfos(objs []*unstructured.Unstructured) ([]*resource.Info, error)
23+
BuildInfo(obj *unstructured.Unstructured) (*resource.Info, error)
2424
}
2525

2626
func NewInfoHelper(factory util.Factory) *infoHelper {
@@ -55,6 +55,26 @@ func (ih *infoHelper) UpdateInfos(infos []*resource.Info) error {
5555
return nil
5656
}
5757

58+
func (ih *infoHelper) UpdateInfo(info *resource.Info) error {
59+
mapper, err := ih.factory.ToRESTMapper()
60+
if err != nil {
61+
return err
62+
}
63+
gvk := info.Object.GetObjectKind().GroupVersionKind()
64+
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
65+
if err != nil {
66+
return err
67+
}
68+
info.Mapping = mapping
69+
70+
c, err := ih.getClient(gvk.GroupVersion())
71+
if err != nil {
72+
return err
73+
}
74+
info.Client = c
75+
return nil
76+
}
77+
5878
func (ih *infoHelper) BuildInfos(objs []*unstructured.Unstructured) ([]*resource.Info, error) {
5979
infos, err := object.UnstructuredsToInfos(objs)
6080
if err != nil {
@@ -67,6 +87,15 @@ func (ih *infoHelper) BuildInfos(objs []*unstructured.Unstructured) ([]*resource
6787
return infos, nil
6888
}
6989

90+
func (ih *infoHelper) BuildInfo(obj *unstructured.Unstructured) (*resource.Info, error) {
91+
info, err := object.UnstructuredToInfo(obj)
92+
if err != nil {
93+
return nil, err
94+
}
95+
err = ih.UpdateInfo(info)
96+
return info, err
97+
}
98+
7099
func (ih *infoHelper) ToRESTMapper() (meta.RESTMapper, error) {
71100
return ih.factory.ToRESTMapper()
72101
}

pkg/apply/task/apply_task.go

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"k8s.io/kubectl/pkg/cmd/delete"
1616
"k8s.io/kubectl/pkg/cmd/util"
1717
"k8s.io/kubectl/pkg/util/slice"
18+
applyerror "sigs.k8s.io/cli-utils/pkg/apply/error"
1819
"sigs.k8s.io/cli-utils/pkg/apply/event"
1920
"sigs.k8s.io/cli-utils/pkg/apply/info"
2021
"sigs.k8s.io/cli-utils/pkg/apply/taskrunner"
@@ -72,22 +73,16 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
7273
// the resource set.
7374
objs, objsWithCRD, err := a.filterCRsWithCRDInSet(objects)
7475
if err != nil {
75-
a.sendTaskResult(taskContext, err)
76+
sendBatchApplyEvents(taskContext, objs, err)
77+
a.sendTaskResult(taskContext)
7678
return
7779
}
7880

7981
// Just send the apply event here. We know it must be a
8082
// Created event since the type didn't already exist in the
8183
// cluster.
8284
for _, obj := range objsWithCRD {
83-
taskContext.EventChannel() <- event.Event{
84-
Type: event.ApplyType,
85-
ApplyEvent: event.ApplyEvent{
86-
Type: event.ApplyEventResourceUpdate,
87-
Operation: event.Created,
88-
Object: obj,
89-
},
90-
}
85+
taskContext.EventChannel() <- createApplyEvent(object.UnstructuredToObjMeta(obj), event.Created, nil)
9186
}
9287
// Update the resource set to no longer include the CRs.
9388
objects = objs
@@ -97,15 +92,7 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
9792
// for that here. It could happen if this is dry-run and we removed
9893
// all resources in the previous step.
9994
if len(objects) == 0 {
100-
a.sendTaskResult(taskContext, nil)
101-
return
102-
}
103-
104-
// Set the client and mapping fields on the provided
105-
// infos so they can be applied to the cluster.
106-
infos, err := a.InfoHelper.BuildInfos(objects)
107-
if err != nil {
108-
a.sendTaskResult(taskContext, err)
95+
a.sendTaskResult(taskContext)
10996
return
11097
}
11198

@@ -114,15 +101,30 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
114101
ao, err := applyOptionsFactoryFunc(taskContext.EventChannel(),
115102
a.ServerSideOptions, a.DryRunStrategy, a.Factory)
116103
if err != nil {
117-
a.sendTaskResult(taskContext, err)
104+
sendBatchApplyEvents(taskContext, objects, err)
105+
a.sendTaskResult(taskContext)
118106
return
119107
}
120-
ao.SetObjects(infos)
121-
err = ao.Run()
122-
if err != nil {
123-
a.sendTaskResult(taskContext, err)
124-
return
108+
109+
var infos []*resource.Info
110+
for _, obj := range objects {
111+
// Set the client and mapping fields on the provided
112+
// info so they can be applied to the cluster.
113+
info, err := a.InfoHelper.BuildInfo(obj)
114+
if err != nil {
115+
taskContext.EventChannel() <- createApplyEvent(
116+
object.UnstructuredToObjMeta(obj), event.Unchanged, applyerror.NewUnknownTypeError(err))
117+
continue
118+
}
119+
infos = append(infos, info)
120+
ao.SetObjects([]*resource.Info{info})
121+
err = ao.Run()
122+
if err != nil {
123+
taskContext.EventChannel() <- createApplyEvent(
124+
object.UnstructuredToObjMeta(obj), event.Unchanged, applyerror.NewApplyRunError(err))
125+
}
125126
}
127+
126128
// Fetch the Generation from all Infos after they have been
127129
// applied.
128130
for _, inf := range infos {
@@ -140,7 +142,7 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) {
140142
taskContext.ResourceApplied(id, uid, gen)
141143
}
142144
}
143-
a.sendTaskResult(taskContext, nil)
145+
a.sendTaskResult(taskContext)
144146
}()
145147
}
146148

@@ -187,10 +189,8 @@ func newApplyOptions(eventChannel chan event.Event, serverSideOptions common.Ser
187189
}, nil
188190
}
189191

190-
func (a *ApplyTask) sendTaskResult(taskContext *taskrunner.TaskContext, err error) {
191-
taskContext.TaskChannel() <- taskrunner.TaskResult{
192-
Err: err,
193-
}
192+
func (a *ApplyTask) sendTaskResult(taskContext *taskrunner.TaskContext) {
193+
taskContext.TaskChannel() <- taskrunner.TaskResult{}
194194
}
195195

196196
// filterCRsWithCRDInSet loops through all the resources and filters out the
@@ -277,3 +277,25 @@ func buildCRDsInfo(crds []*unstructured.Unstructured) *crdsInfo {
277277

278278
// ClearTimeout is not supported by the ApplyTask.
279279
func (a *ApplyTask) ClearTimeout() {}
280+
281+
// createApplyEvent is a helper function to package an apply event for a single resource.
282+
func createApplyEvent(id object.ObjMetadata, operation event.ApplyEventOperation, err error) event.Event {
283+
return event.Event{
284+
Type: event.ApplyType,
285+
ApplyEvent: event.ApplyEvent{
286+
Type: event.ApplyEventResourceUpdate,
287+
Operation: operation,
288+
Identifier: id,
289+
Error: err,
290+
},
291+
}
292+
}
293+
294+
// sendBatchApplyEvents is a helper function to send out multiple apply events for
295+
// a list of resources when failed to initialize the apply process.
296+
func sendBatchApplyEvents(taskContext *taskrunner.TaskContext, objects []*unstructured.Unstructured, err error) {
297+
for _, obj := range objects {
298+
taskContext.EventChannel() <- createApplyEvent(
299+
object.UnstructuredToObjMeta(obj), event.Unchanged, applyerror.NewInitializeApplyOptionError(err))
300+
}
301+
}

0 commit comments

Comments
 (0)