github.com/oam-dev/kubevela@v1.9.11/pkg/config/writer/nacos.go (about) 1 /* 2 Copyright 2022 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 writer 18 19 import ( 20 "context" 21 "fmt" 22 "runtime/debug" 23 "strings" 24 25 "github.com/nacos-group/nacos-sdk-go/v2/clients" 26 "github.com/nacos-group/nacos-sdk-go/v2/clients/config_client" 27 "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 28 "github.com/nacos-group/nacos-sdk-go/v2/vo" 29 "k8s.io/klog/v2" 30 31 "github.com/kubevela/workflow/pkg/cue/model/value" 32 33 "github.com/oam-dev/kubevela/apis/types" 34 icontext "github.com/oam-dev/kubevela/pkg/config/context" 35 "github.com/oam-dev/kubevela/pkg/cue" 36 "github.com/oam-dev/kubevela/pkg/cue/script" 37 ) 38 39 // NacosConfig defines the nacos output 40 type NacosConfig struct { 41 Endpoint ConfigRef `json:"endpoint"` 42 // Format defines the format in which Data will be output. 43 Format string `json:"format"` 44 Metadata NacosConfigMetadata `json:"metadata"` 45 } 46 47 // NacosConfigMetadata the metadata of the nacos config 48 type NacosConfigMetadata struct { 49 DataID string `json:"dataId"` 50 Group string `json:"group"` 51 NamespaceID string `json:"namespaceId"` 52 AppName string `json:"appName,omitempty"` 53 Tenant string `json:"tenant,omitempty"` 54 Tag string `json:"tag,omitempty"` 55 } 56 57 // NacosData merge the nacos endpoint config and the rendered data 58 type NacosData struct { 59 NacosConfig 60 Content []byte `json:"-"` 61 Client config_client.IConfigClient `json:"-"` 62 } 63 64 // parseNacosConfig parse the nacos server config 65 func parseNacosConfig(templateField *value.Value, wc *ExpandedWriterConfig) { 66 nacos, _ := templateField.LookupValue("nacos") 67 if nacos != nil { 68 format, err := nacos.GetString("format") 69 if err != nil && !cue.IsFieldNotExist(err) { 70 klog.Warningf("fail to get the format from the nacos config: %s", err.Error()) 71 } 72 endpoint, err := nacos.GetString("endpoint", "name") 73 if err != nil && !cue.IsFieldNotExist(err) { 74 klog.Warningf("fail to get the endpoint name from the nacos config: %s", err.Error()) 75 } 76 wc.Nacos = &NacosConfig{ 77 Format: format, 78 Endpoint: ConfigRef{ 79 Name: endpoint, 80 }, 81 } 82 } 83 } 84 85 func renderNacos(config *NacosConfig, template script.CUE, context icontext.ConfigRenderContext, properties map[string]interface{}) (*NacosData, error) { 86 nacos, err := template.RunAndOutput(context, properties, "template", "nacos") 87 if err != nil { 88 return nil, err 89 } 90 format, err := nacos.GetString("format") 91 if err != nil { 92 format = config.Format 93 } 94 var nacosData NacosData 95 if err := nacos.UnmarshalTo(&nacosData); err != nil { 96 return nil, err 97 } 98 content, err := nacos.LookupValue("content") 99 if err != nil { 100 return nil, err 101 } 102 103 out, err := encodingOutput(content, format) 104 if err != nil { 105 return nil, err 106 } 107 nacosData.Content = out 108 if nacosData.Endpoint.Namespace == "" { 109 nacosData.Endpoint.Namespace = types.DefaultKubeVelaNS 110 } 111 112 return &nacosData, nil 113 } 114 115 func (n *NacosData) write(ctx context.Context, configReader icontext.ReadConfigProvider) (err error) { 116 defer func() { 117 if rec := recover(); rec != nil { 118 err = fmt.Errorf("panic when writing the data to nacos:%v", rec) 119 debug.PrintStack() 120 } 121 }() 122 // the config of the nacos server saving in the default system namespace 123 config, err := configReader(ctx, n.Endpoint.Namespace, n.Endpoint.Name) 124 if err != nil { 125 return fmt.Errorf("fail to read the config of the nacos server:%w", err) 126 } 127 readString := func(data map[string]interface{}, key string) string { 128 if v, ok := data[key]; ok { 129 str, _ := v.(string) 130 return str 131 } 132 return "" 133 } 134 readUint64 := func(data map[string]interface{}, key string) uint64 { 135 if v, ok := data[key]; ok { 136 vu, _ := v.(float64) 137 return uint64(vu) 138 } 139 return 0 140 } 141 readBool := func(data map[string]interface{}, key string) bool { 142 if v, ok := data[key]; ok { 143 vu, _ := v.(bool) 144 return vu 145 } 146 return false 147 } 148 var nacosParam vo.NacosClientParam 149 if serverConfigs, ok := config["servers"]; ok { 150 var servers []constant.ServerConfig 151 serverEndpoints, _ := serverConfigs.([]interface{}) 152 for _, s := range serverEndpoints { 153 sm, ok := s.(map[string]interface{}) 154 if ok && sm != nil { 155 servers = append(servers, constant.ServerConfig{ 156 IpAddr: readString(sm, "ipAddr"), 157 Port: readUint64(sm, "port"), 158 GrpcPort: readUint64(sm, "grpcPort"), 159 }) 160 } 161 } 162 nacosParam.ServerConfigs = servers 163 } 164 // Discover the server endpoint 165 if clientConfigs, ok := config["client"]; ok { 166 client, _ := clientConfigs.(map[string]interface{}) 167 if client != nil { 168 nacosParam.ClientConfig = constant.NewClientConfig( 169 constant.WithEndpoint(readString(client, "endpoint")), 170 constant.WithAppName(n.Metadata.AppName), 171 constant.WithNamespaceId(n.Metadata.NamespaceID), 172 constant.WithUsername(readString(client, "username")), 173 constant.WithPassword(readString(client, "password")), 174 constant.WithRegionId(readString(client, "regionId")), 175 constant.WithOpenKMS(readBool(client, "openKMS")), 176 constant.WithAccessKey(readString(client, "accessKey")), 177 constant.WithSecretKey(readString(client, "secretKey")), 178 ) 179 } 180 } 181 // The mock client creates on the outer. 182 if n.Client == nil { 183 nacosClient, err := clients.NewConfigClient(nacosParam) 184 if err != nil { 185 return err 186 } 187 defer nacosClient.CloseClient() 188 n.Client = nacosClient 189 } 190 _, err = n.Client.PublishConfig(vo.ConfigParam{ 191 DataId: n.Metadata.DataID, 192 Group: n.Metadata.Group, 193 Content: string(n.Content), 194 AppName: n.Metadata.AppName, 195 Tag: n.Metadata.Tag, 196 Type: strings.ToLower(n.Format), 197 }) 198 if err != nil { 199 return fmt.Errorf("fail to publish the config to the nacos server:%w", err) 200 } 201 return nil 202 }