github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/model/transform_utils.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package model
    21  
    22  import (
    23  	"fmt"
    24  	"reflect"
    25  	"time"
    26  
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apimachinery/pkg/runtime/schema"
    30  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
    33  
    34  	"github.com/1aal/kubeblocks/pkg/controller/graph"
    35  )
    36  
    37  func FindRootVertex(dag *graph.DAG) (*ObjectVertex, error) {
    38  	root := dag.Root()
    39  	if root == nil {
    40  		return nil, fmt.Errorf("root vertex not found: %v", dag)
    41  	}
    42  	rootVertex, _ := root.(*ObjectVertex)
    43  	return rootVertex, nil
    44  }
    45  
    46  func GetGVKName(object client.Object) (*GVKNObjKey, error) {
    47  	gvk, err := apiutil.GVKForObject(object, scheme)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	return &GVKNObjKey{
    52  		GroupVersionKind: gvk,
    53  		ObjectKey:        client.ObjectKeyFromObject(object),
    54  	}, nil
    55  }
    56  
    57  func AddScheme(addToScheme func(*runtime.Scheme) error) {
    58  	utilruntime.Must(addToScheme(scheme))
    59  }
    60  
    61  func GetScheme() *runtime.Scheme {
    62  	return scheme
    63  }
    64  
    65  func IsOwnerOf(owner, obj client.Object) bool {
    66  	ro, ok := owner.(runtime.Object)
    67  	if !ok {
    68  		return false
    69  	}
    70  	gvk, err := apiutil.GVKForObject(ro, scheme)
    71  	if err != nil {
    72  		return false
    73  	}
    74  	ref := metav1.OwnerReference{
    75  		APIVersion: gvk.GroupVersion().String(),
    76  		Kind:       gvk.Kind,
    77  		UID:        owner.GetUID(),
    78  		Name:       owner.GetName(),
    79  	}
    80  	owners := obj.GetOwnerReferences()
    81  	referSameObject := func(a, b metav1.OwnerReference) bool {
    82  		aGV, err := schema.ParseGroupVersion(a.APIVersion)
    83  		if err != nil {
    84  			return false
    85  		}
    86  
    87  		bGV, err := schema.ParseGroupVersion(b.APIVersion)
    88  		if err != nil {
    89  			return false
    90  		}
    91  
    92  		return aGV.Group == bGV.Group && a.Kind == b.Kind && a.Name == b.Name
    93  	}
    94  	for _, ownerRef := range owners {
    95  		if referSameObject(ownerRef, ref) {
    96  			return true
    97  		}
    98  	}
    99  	return false
   100  }
   101  
   102  func actionPtr(action Action) *Action {
   103  	return &action
   104  }
   105  
   106  func ActionCreatePtr() *Action {
   107  	return actionPtr(CREATE)
   108  }
   109  
   110  func ActionDeletePtr() *Action {
   111  	return actionPtr(DELETE)
   112  }
   113  
   114  func ActionUpdatePtr() *Action {
   115  	return actionPtr(UPDATE)
   116  }
   117  
   118  func ActionPatchPtr() *Action {
   119  	return actionPtr(PATCH)
   120  }
   121  
   122  func ActionStatusPtr() *Action {
   123  	return actionPtr(STATUS)
   124  }
   125  
   126  func ActionNoopPtr() *Action {
   127  	return actionPtr(NOOP)
   128  }
   129  
   130  func NewRequeueError(after time.Duration, reason string) error {
   131  	return &realRequeueError{
   132  		reason:       reason,
   133  		requeueAfter: after,
   134  	}
   135  }
   136  
   137  func IsObjectDeleting(object client.Object) bool {
   138  	return !object.GetDeletionTimestamp().IsZero()
   139  }
   140  
   141  func IsObjectUpdating(object client.Object) bool {
   142  	value := reflect.ValueOf(object)
   143  	if value.Kind() == reflect.Ptr {
   144  		value = value.Elem()
   145  	}
   146  	if value.Kind() != reflect.Struct {
   147  		return false
   148  	}
   149  	status := value.FieldByName("Status")
   150  	if !status.IsValid() {
   151  		return false
   152  	}
   153  	observedGeneration := status.FieldByName("ObservedGeneration")
   154  	if !observedGeneration.IsValid() {
   155  		return false
   156  	}
   157  	generation := value.FieldByName("Generation")
   158  	if !generation.IsValid() {
   159  		return false
   160  	}
   161  	return observedGeneration.Interface() != generation.Interface()
   162  }
   163  
   164  func IsObjectStatusUpdating(object client.Object) bool {
   165  	return !IsObjectDeleting(object) && !IsObjectUpdating(object)
   166  }
   167  
   168  // ReadCacheSnapshot reads all objects owned by our cluster
   169  func ReadCacheSnapshot(transCtx graph.TransformContext, root client.Object, ml client.MatchingLabels, kinds ...client.ObjectList) (ObjectSnapshot, error) {
   170  	// list what kinds of object cluster owns
   171  	snapshot := make(ObjectSnapshot)
   172  	inNS := client.InNamespace(root.GetNamespace())
   173  	for _, list := range kinds {
   174  		if err := transCtx.GetClient().List(transCtx.GetContext(), list, inNS, ml); err != nil {
   175  			return nil, err
   176  		}
   177  		// reflect get list.Items
   178  		items := reflect.ValueOf(list).Elem().FieldByName("Items")
   179  		l := items.Len()
   180  		for i := 0; i < l; i++ {
   181  			// get the underlying object
   182  			object := items.Index(i).Addr().Interface().(client.Object)
   183  			name, err := GetGVKName(object)
   184  			if err != nil {
   185  				return nil, err
   186  			}
   187  			snapshot[*name] = object
   188  		}
   189  	}
   190  
   191  	return snapshot, nil
   192  }
   193  
   194  func DefaultLess(v1, v2 graph.Vertex) bool {
   195  	o1, ok1 := v1.(*ObjectVertex)
   196  	o2, ok2 := v2.(*ObjectVertex)
   197  	if !ok1 || !ok2 {
   198  		return false
   199  	}
   200  	return o1.String() < o2.String()
   201  }