github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/transformer_component.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 apps 21 22 import ( 23 "fmt" 24 25 "k8s.io/apimachinery/pkg/util/sets" 26 "sigs.k8s.io/controller-runtime/pkg/client" 27 28 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 29 "github.com/1aal/kubeblocks/controllers/apps/components" 30 "github.com/1aal/kubeblocks/pkg/controller/builder" 31 "github.com/1aal/kubeblocks/pkg/controller/graph" 32 "github.com/1aal/kubeblocks/pkg/controller/model" 33 ictrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 34 ) 35 36 // ComponentTransformer transforms all components to a K8s objects DAG 37 type ComponentTransformer struct { 38 client.Client 39 } 40 41 var _ graph.Transformer = &ComponentTransformer{} 42 43 func (c *ComponentTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error { 44 transCtx, _ := ctx.(*clusterTransformContext) 45 cluster := transCtx.Cluster 46 47 clusterDef := transCtx.ClusterDef 48 clusterVer := transCtx.ClusterVer 49 reqCtx := ictrlutil.RequestCtx{ 50 Ctx: transCtx.Context, 51 Log: transCtx.Logger, 52 Recorder: transCtx.EventRecorder, 53 } 54 55 var err error 56 dags4Component := make([]*graph.DAG, 0) 57 if cluster.IsStatusUpdating() { 58 // status existed components 59 err = c.transform4StatusUpdate(reqCtx, clusterDef, clusterVer, cluster, &dags4Component) 60 } else { 61 // create new components or update existed components 62 err = c.transform4SpecUpdate(reqCtx, clusterDef, clusterVer, cluster, &dags4Component) 63 } 64 if err != nil && !ictrlutil.IsDelayedRequeueError(err) { 65 return err 66 } 67 68 for _, subDag := range dags4Component { 69 for _, v := range subDag.Vertices() { 70 node, ok := v.(*model.ObjectVertex) 71 if !ok { 72 panic("runtime error, unexpected lifecycle vertex type") 73 } 74 if node.Obj == nil { 75 panic("runtime error, nil vertex object") 76 } 77 } 78 dag.Merge(subDag) 79 } 80 return err 81 } 82 83 func (c *ComponentTransformer) transform4SpecUpdate(reqCtx ictrlutil.RequestCtx, clusterDef *appsv1alpha1.ClusterDefinition, 84 clusterVer *appsv1alpha1.ClusterVersion, cluster *appsv1alpha1.Cluster, dags *[]*graph.DAG) error { 85 compSpecMap := make(map[string]*appsv1alpha1.ClusterComponentSpec) 86 compDefMap := make(map[string]*appsv1alpha1.ClusterComponentDefinition) 87 for _, spec := range cluster.Spec.ComponentSpecs { 88 compSpecMap[spec.Name] = &spec 89 } 90 for _, compDef := range clusterDef.Spec.ComponentDefs { 91 compDefMap[compDef.Name] = &compDef 92 } 93 compProto := sets.KeySet(compSpecMap) 94 // if component spec is empty, generate the component spec from cluster template and cluster 95 if cluster.Spec.ComponentSpecs == nil { 96 compProto = sets.KeySet(compDefMap) 97 } 98 // TODO(refactor): should review that whether it is reasonable to use component status 99 compStatus := sets.KeySet(cluster.Status.Components) 100 101 createSet := compProto.Difference(compStatus) 102 updateSet := compProto.Intersection(compStatus) 103 deleteSet := compStatus.Difference(compProto) 104 105 for compName := range createSet { 106 dag := newDAGWithPlaceholder(cluster.Namespace, cluster.Name, compName) 107 comp, err := components.NewComponent(reqCtx, c.Client, clusterDef, clusterVer, cluster, compName, dag) 108 if err != nil { 109 return err 110 } 111 if comp == nil { 112 continue 113 } 114 if err := comp.Create(reqCtx, c.Client); err != nil { 115 return err 116 } 117 *dags = append(*dags, dag) 118 } 119 120 for compName := range deleteSet { 121 dag := newDAGWithPlaceholder(cluster.Namespace, cluster.Name, compName) 122 comp, err := components.NewComponent(reqCtx, c.Client, clusterDef, clusterVer, cluster, compName, dag) 123 if err != nil { 124 return err 125 } 126 if comp == nil { 127 continue 128 } 129 if err := comp.Delete(reqCtx, c.Client); err != nil { 130 return err 131 } 132 *dags = append(*dags, dag) 133 } 134 135 for compName := range updateSet { 136 dag := newDAGWithPlaceholder(cluster.Namespace, cluster.Name, compName) 137 comp, err := components.NewComponent(reqCtx, c.Client, clusterDef, clusterVer, cluster, compName, dag) 138 if err != nil { 139 return err 140 } 141 if err := comp.Update(reqCtx, c.Client); err != nil { 142 return err 143 } 144 *dags = append(*dags, dag) 145 } 146 147 return nil 148 } 149 150 func (c *ComponentTransformer) transform4StatusUpdate(reqCtx ictrlutil.RequestCtx, clusterDef *appsv1alpha1.ClusterDefinition, 151 clusterVer *appsv1alpha1.ClusterVersion, cluster *appsv1alpha1.Cluster, dags *[]*graph.DAG) error { 152 var delayedError error 153 for _, compSpec := range cluster.Spec.ComponentSpecs { 154 dag := newDAGWithPlaceholder(cluster.Namespace, cluster.Name, compSpec.Name) 155 comp, err := components.NewComponent(reqCtx, c.Client, clusterDef, clusterVer, cluster, compSpec.Name, dag) 156 if err != nil { 157 return err 158 } 159 if err := comp.Status(reqCtx, c.Client); err != nil { 160 if !ictrlutil.IsDelayedRequeueError(err) { 161 return err 162 } 163 if delayedError == nil { 164 delayedError = err 165 } 166 } 167 *dags = append(*dags, dag) 168 } 169 return delayedError 170 } 171 172 func newDAGWithPlaceholder(namespace, clusterName, compName string) *graph.DAG { 173 root := builder.NewReplicatedStateMachineBuilder(namespace, fmt.Sprintf("%s-%s", clusterName, compName)).GetObject() 174 dag := graph.NewDAG() 175 model.NewGraphClient(nil).Root(dag, nil, root, nil) 176 return dag 177 }