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  }