github.com/oam-dev/kubevela@v1.9.11/pkg/config/writer/writer.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  	"encoding/json"
    22  	"fmt"
    23  	"reflect"
    24  	"strings"
    25  
    26  	"cuelang.org/go/cue"
    27  
    28  	"github.com/magiconair/properties"
    29  	"github.com/pelletier/go-toml"
    30  	"gopkg.in/yaml.v3"
    31  	"k8s.io/klog/v2"
    32  
    33  	"github.com/kubevela/workflow/pkg/cue/model/value"
    34  
    35  	icontext "github.com/oam-dev/kubevela/pkg/config/context"
    36  	"github.com/oam-dev/kubevela/pkg/cue/script"
    37  )
    38  
    39  // ExpandedWriterConfig define the supported output ways.
    40  type ExpandedWriterConfig struct {
    41  	Nacos *NacosConfig `json:"nacos"`
    42  }
    43  
    44  // ExpandedWriterData the data for the expanded writer
    45  type ExpandedWriterData struct {
    46  	Nacos *NacosData `json:"nacos"`
    47  }
    48  
    49  // ConfigRef reference a config secret, it must be system scope.
    50  type ConfigRef struct {
    51  	Name      string `json:"name"`
    52  	Namespace string `json:"namespace"`
    53  }
    54  
    55  // ParseExpandedWriterConfig parse the expanded writer config from the template value
    56  func ParseExpandedWriterConfig(template cue.Value) ExpandedWriterConfig {
    57  	var ewc = ExpandedWriterConfig{}
    58  	nacos := template.LookupPath(cue.ParsePath("nacos"))
    59  	if nacos.Exists() {
    60  		nacosConfig := &NacosConfig{}
    61  		if err := nacos.Decode(&nacosConfig); err != nil {
    62  			klog.Warningf("failed to decode the nacos config: %s", err.Error())
    63  		}
    64  		ewc.Nacos = nacosConfig
    65  	}
    66  	// parse the other writer configs
    67  	return ewc
    68  }
    69  
    70  // RenderForExpandedWriter render the configuration for all expanded writers
    71  func RenderForExpandedWriter(ewc ExpandedWriterConfig, template script.CUE, context icontext.ConfigRenderContext, properties map[string]interface{}) (*ExpandedWriterData, error) {
    72  	var ewd = ExpandedWriterData{}
    73  	var err error
    74  	if ewc.Nacos != nil {
    75  		ewd.Nacos, err = renderNacos(ewc.Nacos, template, context, properties)
    76  		if err != nil {
    77  			return nil, err
    78  		}
    79  		klog.Info("the config render to nacos context successfully")
    80  	}
    81  	return &ewd, nil
    82  }
    83  
    84  // Write write the config by the all writers
    85  func Write(ctx context.Context, ewd *ExpandedWriterData, ri icontext.ReadConfigProvider) (list []error) {
    86  	if ewd.Nacos != nil {
    87  		if err := ewd.Nacos.write(ctx, ri); err != nil {
    88  			list = append(list, err)
    89  		} else {
    90  			klog.Info("the config write to the nacos successfully")
    91  		}
    92  	}
    93  	return
    94  }
    95  
    96  // encodingOutput support the json、toml、xml、properties and yaml formats.
    97  func encodingOutput(input *value.Value, format string) ([]byte, error) {
    98  	var data = make(map[string]interface{})
    99  	if err := input.UnmarshalTo(&data); err != nil {
   100  		return nil, err
   101  	}
   102  	switch strings.ToLower(format) {
   103  	case "json":
   104  		return json.Marshal(data)
   105  	case "toml":
   106  		return toml.Marshal(data)
   107  	case "properties":
   108  		var kv = map[string]string{}
   109  		if err := convertMap2PropertiesKV("", data, kv); err != nil {
   110  			return nil, err
   111  		}
   112  		return []byte(properties.LoadMap(kv).String()), nil
   113  	default:
   114  		return yaml.Marshal(data)
   115  	}
   116  }
   117  
   118  func convertMap2PropertiesKV(last string, input map[string]interface{}, result map[string]string) error {
   119  
   120  	interface2str := func(key string, v interface{}, result map[string]string) (string, error) {
   121  		switch t := v.(type) {
   122  		case string:
   123  			return t, nil
   124  		case bool:
   125  			return fmt.Sprintf("%t", t), nil
   126  		case int64, int, int32:
   127  			return fmt.Sprintf("%d", t), nil
   128  		case float64, float32:
   129  			return fmt.Sprintf("%v", t), nil
   130  		case map[string]interface{}:
   131  			if err := convertMap2PropertiesKV(key, t, result); err != nil {
   132  				return "", err
   133  			}
   134  			return "", nil
   135  		default:
   136  			return fmt.Sprintf("%v", t), nil
   137  		}
   138  	}
   139  
   140  	for k, v := range input {
   141  		key := k
   142  		if last != "" {
   143  			key = fmt.Sprintf("%s.%s", last, k)
   144  		}
   145  		switch t := v.(type) {
   146  		case string, bool, int64, int, int32, float32, float64, map[string]interface{}:
   147  			v, err := interface2str(key, t, result)
   148  			if err != nil {
   149  				return err
   150  			}
   151  			if v != "" {
   152  				result[key] = v
   153  			}
   154  		case []interface{}, []string, []int64, []float64, []map[string]interface{}:
   155  			var ints []string
   156  			s := reflect.ValueOf(t)
   157  			for i := 0; i < s.Len(); i++ {
   158  				re, err := interface2str(fmt.Sprintf("%s.%d", key, i), s.Index(i).Interface(), result)
   159  				if err != nil {
   160  					return err
   161  				}
   162  				if re != "" {
   163  					ints = append(ints, re)
   164  				}
   165  			}
   166  			if len(ints) > 0 {
   167  				result[key] = strings.Join(ints, ",")
   168  			}
   169  		default:
   170  			return fmt.Errorf("the value type of %s(%T) can not be supported", key, t)
   171  		}
   172  	}
   173  	return nil
   174  }