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 }