github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/configuration/config_template_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 configuration 21 22 import ( 23 "context" 24 "fmt" 25 26 corev1 "k8s.io/api/core/v1" 27 "k8s.io/apimachinery/pkg/types" 28 29 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 30 ictrlclient "github.com/1aal/kubeblocks/pkg/controller/client" 31 "github.com/1aal/kubeblocks/pkg/controller/component" 32 ) 33 34 type Visitor interface { 35 Visit(VisitorFunc) error 36 } 37 38 type VisitorFunc func(*component.SynthesizedComponent, error) error 39 40 // DecoratedVisitor will invoke the decorators in order prior to invoking the visitor function 41 // passed to Visit. An error will terminate the visit. 42 type DecoratedVisitor struct { 43 visitor Visitor 44 decorators []VisitorFunc 45 } 46 47 // NewDecoratedVisitor will create a visitor that invokes the provided visitor functions before 48 // the user supplied visitor function is invoked, giving them the opportunity to mutate the Info 49 // object or terminate early with an error. 50 func NewDecoratedVisitor(v Visitor, fn ...VisitorFunc) Visitor { 51 if len(fn) == 0 { 52 return v 53 } 54 return DecoratedVisitor{v, fn} 55 } 56 57 // Visit implements Visitor 58 func (v DecoratedVisitor) Visit(fn VisitorFunc) error { 59 return v.visitor.Visit(func(component *component.SynthesizedComponent, err error) error { 60 if err != nil { 61 return err 62 } 63 for i := range v.decorators { 64 if err := v.decorators[i](component, nil); err != nil { 65 return err 66 } 67 } 68 return fn(component, nil) 69 }) 70 } 71 72 // ComponentVisitor implements Visitor, it will visit the component.SynthesizedComponent 73 type ComponentVisitor struct { 74 component *component.SynthesizedComponent 75 } 76 77 // Visit implements Visitor 78 func (r *ComponentVisitor) Visit(fn VisitorFunc) error { 79 return fn(r.component, nil) 80 } 81 82 // resolveServiceReferences is the visitor function to resolve the service reference 83 func resolveServiceReferences(cli ictrlclient.ReadonlyClient, ctx context.Context) VisitorFunc { 84 return func(component *component.SynthesizedComponent, err error) error { 85 if err != nil { 86 return err 87 } 88 if component.ServiceReferences == nil { 89 return nil 90 } 91 for _, serviceDescriptor := range component.ServiceReferences { 92 // TODO: currently, only support endpoint and port, serviceDescriptor.Spec.Auth is not supported 93 if err := resolveCredentialVar(cli, ctx, serviceDescriptor.Namespace, serviceDescriptor.Spec.Endpoint, serviceDescriptor.Spec.Port); err != nil { 94 return err 95 } 96 } 97 return nil 98 } 99 } 100 101 // resolveCredentialVar resolve the credentialVar.ValueFrom to the real value 102 // TODO: currently, we set the valueFrom to the value, which need to be refactored 103 func resolveCredentialVar(cli ictrlclient.ReadonlyClient, ctx context.Context, namespace string, credentialVars ...*appsv1alpha1.CredentialVar) error { 104 resolveSecretKeyRef := func(credentialVar *appsv1alpha1.CredentialVar) error { 105 if credentialVar.ValueFrom == nil || credentialVar.ValueFrom.SecretKeyRef == nil { 106 return nil 107 } 108 secretName := credentialVar.ValueFrom.SecretKeyRef.Name 109 secretKey := credentialVar.ValueFrom.SecretKeyRef.Key 110 secretRef := &corev1.Secret{} 111 if err := cli.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secretRef); err != nil { 112 return err 113 } 114 runtimeValBytes, ok := secretRef.Data[secretKey] 115 if !ok { 116 return fmt.Errorf("couldn't find key %v in Secret %v/%v", secretKey, namespace, secretName) 117 } 118 // Set the valueFrom to the value and clear the valueFrom 119 credentialVar.ValueFrom = nil 120 credentialVar.Value = string(runtimeValBytes) 121 return nil 122 } 123 124 resolveConfigMapKeyRef := func(credentialVar *appsv1alpha1.CredentialVar) error { 125 if credentialVar.ValueFrom == nil || credentialVar.ValueFrom.ConfigMapKeyRef == nil { 126 return nil 127 } 128 configMapName := credentialVar.ValueFrom.ConfigMapKeyRef.Name 129 configMapKey := credentialVar.ValueFrom.ConfigMapKeyRef.Key 130 configMapRef := &corev1.ConfigMap{} 131 if err := cli.Get(ctx, types.NamespacedName{Name: configMapName, Namespace: namespace}, configMapRef); err != nil { 132 return err 133 } 134 runtimeValBytes, ok := configMapRef.Data[configMapKey] 135 if !ok { 136 return fmt.Errorf("couldn't find key %v in ConfigMap %v/%v", configMapKey, namespace, configMapName) 137 } 138 // Set the valueFrom to the value and clear the valueFrom 139 credentialVar.ValueFrom = nil 140 credentialVar.Value = runtimeValBytes 141 return nil 142 } 143 144 if len(credentialVars) == 0 { 145 return nil 146 } 147 148 for _, credentialVar := range credentialVars { 149 // TODO: replace thw build-in placeholder with the real value 150 if credentialVar.Value != "" { 151 return nil 152 } 153 // TODO: currently, we set the valueFrom to the value, which need to be refactored 154 if credentialVar.ValueFrom != nil { 155 if err := resolveSecretKeyRef(credentialVar); err != nil { 156 return err 157 } 158 if err := resolveConfigMapKeyRef(credentialVar); err != nil { 159 return err 160 } 161 } 162 } 163 return nil 164 }