vitess.io/vitess@v0.16.2/go/vt/vtadmin/cluster/file_config.go (about) 1 /* 2 Copyright 2020 The Vitess 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 cluster 18 19 import ( 20 "strings" 21 22 "github.com/spf13/viper" 23 ) 24 25 // FileConfig represents the structure of a set of cluster configs on disk. It 26 // contains both a default config, and cluster-specific overrides. Viper is used 27 // internally to load the config file, so any file format supported by viper is 28 // permitted. 29 // 30 // A valid YAML config looks like: 31 // 32 // defaults: 33 // discovery: k8s 34 // clusters: 35 // clusterID1: 36 // name: clusterName1 37 // discovery-k8s-some-flag: some-val 38 // clusterID2: 39 // name: clusterName2 40 // discovery: consul 41 type FileConfig struct { 42 Defaults Config 43 Clusters map[string]Config 44 } 45 46 // String is part of the flag.Value interface. 47 func (fc *FileConfig) String() string { 48 buf := strings.Builder{} 49 50 // inlining this produces "String is not in the method set of ClustersFlag" 51 cf := ClustersFlag(fc.Clusters) 52 53 buf.WriteString("{defaults: ") 54 buf.WriteString(fc.Defaults.String()) 55 buf.WriteString(", clusters: ") 56 buf.WriteString(cf.String()) 57 buf.WriteString("}") 58 59 return buf.String() 60 } 61 62 // Type is part of the pflag.Value interface. 63 func (fc *FileConfig) Type() string { 64 return "cluster.FileConfig" 65 } 66 67 // Set is part of the flag.Value interface. It loads the file configuration 68 // found at the path passed to the flag. Any config file format supported by 69 // viper is supported by FileConfig. 70 func (fc *FileConfig) Set(value string) error { 71 v := viper.New() 72 v.SetConfigFile(value) 73 if err := v.ReadInConfig(); err != nil { 74 return err 75 } 76 77 return fc.unmarshalViper(v) 78 } 79 80 func (fc *FileConfig) unmarshalViper(v *viper.Viper) error { 81 tmp := struct { // work around mapstructure's interface; see https://github.com/spf13/viper/issues/338#issuecomment-382376136 82 Defaults map[string]string 83 Clusters map[string]map[string]string 84 }{ 85 Defaults: map[string]string{}, 86 Clusters: map[string]map[string]string{}, 87 } 88 89 if err := v.Unmarshal(&tmp); err != nil { 90 return err 91 } 92 93 if err := fc.Defaults.unmarshalMap(tmp.Defaults); err != nil { 94 return err 95 } 96 97 if fc.Clusters == nil { 98 fc.Clusters = map[string]Config{} 99 } 100 for id, clusterMap := range tmp.Clusters { 101 c, ok := fc.Clusters[id] 102 if !ok { 103 c = Config{ 104 ID: id, 105 DiscoveryFlagsByImpl: map[string]map[string]string{}, 106 VtSQLFlags: map[string]string{}, 107 VtctldFlags: map[string]string{}, 108 } 109 } 110 111 if err := c.unmarshalMap(clusterMap); err != nil { 112 return err 113 } 114 115 fc.Clusters[id] = c 116 } 117 118 return nil 119 } 120 121 // Combine combines a FileConfig with a default Config and a ClustersFlag (each 122 // defined on the command-line) into a slice of final Configs that are suitable 123 // to use for cluster creation. 124 // 125 // Combination uses the following precedence: 126 // 1. Command-line cluster-specific overrides. 127 // 2. File-based cluster-specific overrides. 128 // 3. Command-line cluster defaults. 129 // 4. File-based cluster defaults. 130 func (fc *FileConfig) Combine(defaults Config, clusters map[string]Config) []Config { 131 configs := make([]Config, 0, len(clusters)) 132 merged := map[string]bool{} 133 134 combinedDefaults := fc.Defaults.Merge(defaults) 135 136 for name, cfg := range fc.Clusters { 137 merged[name] = true 138 139 override, ok := clusters[name] 140 if !ok { 141 configs = append(configs, combinedDefaults.Merge(cfg)) 142 continue 143 } 144 145 combinedOverrides := cfg.Merge(override) 146 configs = append(configs, combinedDefaults.Merge(combinedOverrides)) 147 } 148 149 for name, cfg := range clusters { 150 if _, ok := merged[name]; ok { 151 continue 152 } 153 154 configs = append(configs, combinedDefaults.Merge(cfg)) 155 } 156 157 return configs 158 }