github.com/oam-dev/kubevela@v1.9.11/pkg/resourcekeeper/resourcekeeper.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package resourcekeeper 18 19 import ( 20 "context" 21 "sync" 22 23 "github.com/pkg/errors" 24 appsv1 "k8s.io/api/apps/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 27 "sigs.k8s.io/controller-runtime/pkg/client" 28 29 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1" 30 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 31 "github.com/oam-dev/kubevela/pkg/multicluster" 32 "github.com/oam-dev/kubevela/pkg/oam" 33 "github.com/oam-dev/kubevela/pkg/policy" 34 "github.com/oam-dev/kubevela/pkg/resourcetracker" 35 "github.com/oam-dev/kubevela/pkg/utils/apply" 36 ) 37 38 // ResourceKeeper handler for dispatching and deleting resources 39 type ResourceKeeper interface { 40 Dispatch(context.Context, []*unstructured.Unstructured, []apply.ApplyOption, ...DispatchOption) error 41 Delete(context.Context, []*unstructured.Unstructured, ...DeleteOption) error 42 GarbageCollect(context.Context, ...GCOption) (bool, []v1beta1.ManagedResource, error) 43 StateKeep(context.Context) error 44 ContainsResources([]*unstructured.Unstructured) bool 45 46 DispatchComponentRevision(context.Context, *appsv1.ControllerRevision) error 47 DeleteComponentRevision(context.Context, *appsv1.ControllerRevision) error 48 } 49 50 type resourceKeeper struct { 51 client.Client 52 app *v1beta1.Application 53 mu sync.Mutex 54 55 applicator apply.Applicator 56 _rootRT *v1beta1.ResourceTracker 57 _currentRT *v1beta1.ResourceTracker 58 _historyRTs []*v1beta1.ResourceTracker 59 _crRT *v1beta1.ResourceTracker 60 61 applyOncePolicy *v1alpha1.ApplyOncePolicySpec 62 garbageCollectPolicy *v1alpha1.GarbageCollectPolicySpec 63 sharedResourcePolicy *v1alpha1.SharedResourcePolicySpec 64 takeOverPolicy *v1alpha1.TakeOverPolicySpec 65 readOnlyPolicy *v1alpha1.ReadOnlyPolicySpec 66 resourceUpdatePolicy *v1alpha1.ResourceUpdatePolicySpec 67 68 cache *resourceCache 69 } 70 71 func (h *resourceKeeper) getRootRT(ctx context.Context) (rootRT *v1beta1.ResourceTracker, err error) { 72 if h._rootRT == nil { 73 if h._rootRT, err = resourcetracker.CreateRootResourceTracker(multicluster.ContextInLocalCluster(ctx), h.Client, h.app); err != nil { 74 return nil, err 75 } 76 } 77 return h._rootRT, nil 78 } 79 80 func (h *resourceKeeper) getCurrentRT(ctx context.Context) (currentRT *v1beta1.ResourceTracker, err error) { 81 if h._currentRT == nil { 82 if h._currentRT, err = resourcetracker.CreateCurrentResourceTracker(multicluster.ContextInLocalCluster(ctx), h.Client, h.app); err != nil { 83 return nil, err 84 } 85 } 86 return h._currentRT, nil 87 } 88 89 func (h *resourceKeeper) getComponentRevisionRT(ctx context.Context) (crRT *v1beta1.ResourceTracker, err error) { 90 if h._crRT == nil { 91 if h._crRT, err = resourcetracker.CreateComponentRevisionResourceTracker(multicluster.ContextInLocalCluster(ctx), h.Client, h.app); err != nil { 92 return nil, err 93 } 94 } 95 return h._crRT, nil 96 } 97 98 func (h *resourceKeeper) parseApplicationResourcePolicy() (err error) { 99 if h.applyOncePolicy, err = policy.ParsePolicy[v1alpha1.ApplyOncePolicySpec](h.app); err != nil { 100 return errors.Wrapf(err, "failed to parse apply-once policy") 101 } 102 if h.applyOncePolicy == nil && metav1.HasLabel(h.app.ObjectMeta, oam.LabelAddonName) { 103 h.applyOncePolicy = &v1alpha1.ApplyOncePolicySpec{Enable: true} 104 } 105 if h.garbageCollectPolicy, err = policy.ParsePolicy[v1alpha1.GarbageCollectPolicySpec](h.app); err != nil { 106 return errors.Wrapf(err, "failed to parse garbage-collect policy") 107 } 108 if h.sharedResourcePolicy, err = policy.ParsePolicy[v1alpha1.SharedResourcePolicySpec](h.app); err != nil { 109 return errors.Wrapf(err, "failed to parse shared-resource policy") 110 } 111 if h.takeOverPolicy, err = policy.ParsePolicy[v1alpha1.TakeOverPolicySpec](h.app); err != nil { 112 return errors.Wrapf(err, "failed to parse take-over policy") 113 } 114 if h.readOnlyPolicy, err = policy.ParsePolicy[v1alpha1.ReadOnlyPolicySpec](h.app); err != nil { 115 return errors.Wrapf(err, "failed to parse read-only policy") 116 } 117 if h.resourceUpdatePolicy, err = policy.ParsePolicy[v1alpha1.ResourceUpdatePolicySpec](h.app); err != nil { 118 return errors.Wrapf(err, "failed to parse resource-update policy") 119 } 120 return nil 121 } 122 123 func (h *resourceKeeper) loadResourceTrackers(ctx context.Context) (err error) { 124 h._rootRT, h._currentRT, h._historyRTs, h._crRT, err = resourcetracker.ListApplicationResourceTrackers(multicluster.ContextInLocalCluster(ctx), h.Client, h.app) 125 return err 126 } 127 128 // NewResourceKeeper create a handler for dispatching and deleting resources 129 func NewResourceKeeper(ctx context.Context, cli client.Client, app *v1beta1.Application) (_ ResourceKeeper, err error) { 130 h := &resourceKeeper{ 131 Client: cli, 132 app: app, 133 applicator: apply.NewAPIApplicator(cli), 134 cache: newResourceCache(cli, app), 135 } 136 if err = h.loadResourceTrackers(ctx); err != nil { 137 return nil, errors.Wrapf(err, "failed to load resourcetrackers") 138 } 139 if err = h.parseApplicationResourcePolicy(); err != nil { 140 return nil, errors.Wrapf(err, "failed to parse resource policy") 141 } 142 return h, nil 143 }