istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/echo/config/source.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package config 16 17 import ( 18 "istio.io/istio/pkg/test" 19 "istio.io/istio/pkg/test/framework/components/echo/config/param" 20 "istio.io/istio/pkg/test/framework/components/namespace" 21 "istio.io/istio/pkg/test/util/file" 22 "istio.io/istio/pkg/test/util/tmpl" 23 "istio.io/istio/pkg/test/util/yml" 24 ) 25 26 // Source of YAML text. 27 type Source interface { 28 // Template reads the raw input and creates a Template from this source. 29 Template() (*param.Template, error) 30 31 // TemplateOrFail calls Template and fails if an error occurs. 32 TemplateOrFail(t test.Failer) *param.Template 33 34 // MustTemplate calls Template and panics if an error occurs. 35 MustTemplate() *param.Template 36 37 // YAML reads the yaml from this Source. If this source contains parameters, 38 // it is evaluated as a template. 39 YAML() (string, error) 40 41 // YAMLOrFail calls GetYAML and fails if an error occurs. 42 YAMLOrFail(t test.Failer) string 43 44 // MustYAML calls GetYAML and panics if an error occurs. 45 MustYAML() string 46 47 // Split this source into individual CRDs. 48 Split() ([]Source, error) 49 50 // SplitOrFail calls Split and fails if an error occurs. 51 SplitOrFail(t test.Failer) []Source 52 53 // MustSplit calls Split and panics if an error occurs. 54 MustSplit() []Source 55 56 // Params returns a copy of the parameters for this Source. 57 Params() param.Params 58 59 // WithParams creates a new Source with the given template parameters. 60 // If a Source contains params, it will be evaluated as a template by GetYAML. 61 // If this source already has parameters, the returned Source will contain 62 // a union of the two sets. If the same entry appears in the existing params, 63 // the new value overwrites the existing. 64 WithParams(params param.Params) Source 65 66 // WithNamespace calls WithParams with the given namespace set. 67 WithNamespace(namespace.Instance) Source 68 } 69 70 // YAML returns a Source of raw YAML text. 71 func YAML(text string) Source { 72 return sourceImpl{ 73 read: func() (string, error) { 74 return text, nil 75 }, 76 } 77 } 78 79 // File returns a Source of YAML text stored in files. 80 func File(filePath string) Source { 81 return sourceImpl{ 82 read: func() (string, error) { 83 return file.AsString(filePath) 84 }, 85 } 86 } 87 88 type sourceImpl struct { 89 read func() (string, error) 90 params param.Params 91 } 92 93 func (s sourceImpl) Template() (*param.Template, error) { 94 raw, err := s.read() 95 if err != nil { 96 return nil, err 97 } 98 99 tpl, err := tmpl.Parse(raw) 100 if err != nil { 101 return nil, err 102 } 103 return param.Parse(tpl), nil 104 } 105 106 func (s sourceImpl) TemplateOrFail(t test.Failer) *param.Template { 107 t.Helper() 108 tpl, err := s.Template() 109 if err != nil { 110 t.Fatal(err) 111 } 112 return tpl 113 } 114 115 func (s sourceImpl) MustTemplate() *param.Template { 116 tpl, err := s.Template() 117 if err != nil { 118 panic(err) 119 } 120 return tpl 121 } 122 123 func (s sourceImpl) YAML() (string, error) { 124 // If params were specified, process the yaml as a template. 125 if s.params != nil { 126 t, err := s.Template() 127 if err != nil { 128 return "", err 129 } 130 return tmpl.Execute(t.Template, s.params) 131 } 132 133 // Otherwise, just read the yaml. 134 return s.read() 135 } 136 137 func (s sourceImpl) YAMLOrFail(t test.Failer) string { 138 t.Helper() 139 out, err := s.YAML() 140 if err != nil { 141 t.Fatal(err) 142 } 143 return out 144 } 145 146 func (s sourceImpl) MustYAML() string { 147 out, err := s.YAML() 148 if err != nil { 149 panic(err) 150 } 151 return out 152 } 153 154 func (s sourceImpl) Split() ([]Source, error) { 155 raw, err := s.read() 156 if err != nil { 157 return nil, err 158 } 159 160 pieces := yml.SplitString(raw) 161 if len(pieces) == 1 { 162 // There was nothing to split. Just return the original source. 163 return []Source{s}, nil 164 } 165 166 out := make([]Source, 0, len(pieces)) 167 for _, p := range pieces { 168 out = append(out, YAML(p).WithParams(s.Params())) 169 } 170 return out, nil 171 } 172 173 func (s sourceImpl) SplitOrFail(t test.Failer) []Source { 174 t.Helper() 175 out, err := s.Split() 176 if err != nil { 177 t.Fatal(err) 178 } 179 return out 180 } 181 182 func (s sourceImpl) MustSplit() []Source { 183 out, err := s.Split() 184 if err != nil { 185 panic(err) 186 } 187 return out 188 } 189 190 func (s sourceImpl) Params() param.Params { 191 return s.params.Copy() 192 } 193 194 func (s sourceImpl) WithParams(params param.Params) Source { 195 if len(params) == 0 { 196 return s 197 } 198 199 // Merge the parameters (if needed). 200 mergedParams := params 201 if len(s.params) > 0 { 202 // Make a copy of params. 203 mergedParams = make(map[string]any, len(params)+len(s.params)) 204 for k, v := range params { 205 mergedParams[k] = v 206 } 207 208 // Copy non-conflicting values from this Source. 209 for k, v := range s.params { 210 if _, ok := mergedParams[k]; !ok { 211 mergedParams[k] = v 212 } 213 } 214 } 215 216 return sourceImpl{ 217 read: s.read, 218 params: mergedParams, 219 } 220 } 221 222 func (s sourceImpl) WithNamespace(ns namespace.Instance) Source { 223 return s.WithParams(param.Params{ 224 param.Namespace.String(): ns, 225 }) 226 }