github.com/Jeffail/benthos/v3@v3.65.0/lib/manager/config.go (about) 1 package manager 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/Jeffail/benthos/v3/lib/cache" 8 "github.com/Jeffail/benthos/v3/lib/condition" 9 "github.com/Jeffail/benthos/v3/lib/input" 10 "github.com/Jeffail/benthos/v3/lib/output" 11 "github.com/Jeffail/benthos/v3/lib/processor" 12 "github.com/Jeffail/benthos/v3/lib/ratelimit" 13 "github.com/Jeffail/benthos/v3/lib/util/config" 14 ) 15 16 // ResourceConfig contains fields for specifying resource components at the root 17 // of a Benthos config. 18 type ResourceConfig struct { 19 // Called manager for backwards compatibility. 20 Manager Config `json:"resources,omitempty" yaml:"resources,omitempty"` 21 ResourceInputs []input.Config `json:"input_resources,omitempty" yaml:"input_resources,omitempty"` 22 ResourceProcessors []processor.Config `json:"processor_resources,omitempty" yaml:"processor_resources,omitempty"` 23 ResourceOutputs []output.Config `json:"output_resources,omitempty" yaml:"output_resources,omitempty"` 24 ResourceCaches []cache.Config `json:"cache_resources,omitempty" yaml:"cache_resources,omitempty"` 25 ResourceRateLimits []ratelimit.Config `json:"rate_limit_resources,omitempty" yaml:"rate_limit_resources,omitempty"` 26 } 27 28 // NewResourceConfig creates a ResourceConfig with default values. 29 func NewResourceConfig() ResourceConfig { 30 return ResourceConfig{ 31 Manager: NewConfig(), 32 ResourceInputs: []input.Config{}, 33 ResourceProcessors: []processor.Config{}, 34 ResourceOutputs: []output.Config{}, 35 ResourceCaches: []cache.Config{}, 36 ResourceRateLimits: []ratelimit.Config{}, 37 } 38 } 39 40 // Collapses all the slice based resources into maps, returning an error if any 41 // labels are duplicated or empty. 42 func (r *ResourceConfig) collapsed() (ResourceConfig, error) { 43 newMaps := NewConfig() 44 45 for k, v := range r.Manager.Caches { 46 newMaps.Caches[k] = v 47 } 48 for _, c := range r.ResourceCaches { 49 if c.Label == "" { 50 return *r, errors.New("cache resource has an empty label") 51 } 52 if _, exists := newMaps.Caches[c.Label]; exists { 53 return *r, fmt.Errorf("cache resource label '%v' collides with a previously defined resource", c.Label) 54 } 55 newMaps.Caches[c.Label] = c 56 } 57 58 for k, v := range r.Manager.Conditions { 59 newMaps.Conditions[k] = v 60 } 61 62 for k, v := range r.Manager.Inputs { 63 newMaps.Inputs[k] = v 64 } 65 for _, c := range r.ResourceInputs { 66 if c.Label == "" { 67 return *r, errors.New("input resource has an empty label") 68 } 69 if _, exists := newMaps.Inputs[c.Label]; exists { 70 return *r, fmt.Errorf("input resource label '%v' collides with a previously defined resource", c.Label) 71 } 72 newMaps.Inputs[c.Label] = c 73 } 74 75 for k, v := range r.Manager.Outputs { 76 newMaps.Outputs[k] = v 77 } 78 for _, c := range r.ResourceOutputs { 79 if c.Label == "" { 80 return *r, errors.New("output resource has an empty label") 81 } 82 if _, exists := newMaps.Outputs[c.Label]; exists { 83 return *r, fmt.Errorf("output resource label '%v' collides with a previously defined resource", c.Label) 84 } 85 newMaps.Outputs[c.Label] = c 86 } 87 88 for k, v := range r.Manager.Plugins { 89 newMaps.Plugins[k] = v 90 } 91 92 for k, v := range r.Manager.Processors { 93 newMaps.Processors[k] = v 94 } 95 for _, c := range r.ResourceProcessors { 96 if c.Label == "" { 97 return *r, errors.New("processor resource has an empty label") 98 } 99 if _, exists := newMaps.Processors[c.Label]; exists { 100 return *r, fmt.Errorf("processor resource label '%v' collides with a previously defined resource", c.Label) 101 } 102 newMaps.Processors[c.Label] = c 103 } 104 105 for k, v := range r.Manager.RateLimits { 106 newMaps.RateLimits[k] = v 107 } 108 for _, c := range r.ResourceRateLimits { 109 if c.Label == "" { 110 return *r, errors.New("rate limit resource has an empty label") 111 } 112 if _, exists := newMaps.RateLimits[c.Label]; exists { 113 return *r, fmt.Errorf("rate limit resource label '%v' collides with a previously defined resource", c.Label) 114 } 115 newMaps.RateLimits[c.Label] = c 116 } 117 118 return ResourceConfig{ 119 Manager: newMaps, 120 }, nil 121 } 122 123 // AddFrom takes another Config and adds all of its resources to itself. If 124 // there are any resource name collisions an error is returned. 125 func (r *ResourceConfig) AddFrom(extra *ResourceConfig) error { 126 if err := r.Manager.AddFrom(&extra.Manager); err != nil { 127 return err 128 } 129 // TODO: Detect duplicates. 130 r.ResourceInputs = append(r.ResourceInputs, extra.ResourceInputs...) 131 r.ResourceProcessors = append(r.ResourceProcessors, extra.ResourceProcessors...) 132 r.ResourceOutputs = append(r.ResourceOutputs, extra.ResourceOutputs...) 133 r.ResourceCaches = append(r.ResourceCaches, extra.ResourceCaches...) 134 r.ResourceRateLimits = append(r.ResourceRateLimits, extra.ResourceRateLimits...) 135 return nil 136 } 137 138 // Config contains all configuration fields for a Benthos service manager. 139 type Config struct { 140 Inputs map[string]input.Config `json:"inputs,omitempty" yaml:"inputs,omitempty"` 141 Conditions map[string]condition.Config `json:"conditions,omitempty" yaml:"conditions,omitempty"` 142 Processors map[string]processor.Config `json:"processors,omitempty" yaml:"processors,omitempty"` 143 Outputs map[string]output.Config `json:"outputs,omitempty" yaml:"outputs,omitempty"` 144 Caches map[string]cache.Config `json:"caches,omitempty" yaml:"caches,omitempty"` 145 RateLimits map[string]ratelimit.Config `json:"rate_limits,omitempty" yaml:"rate_limits,omitempty"` 146 Plugins map[string]PluginConfig `json:"plugins,omitempty" yaml:"plugins,omitempty"` 147 } 148 149 // NewConfig returns a Config with default values. 150 func NewConfig() Config { 151 return Config{ 152 Inputs: map[string]input.Config{}, 153 Conditions: map[string]condition.Config{}, 154 Processors: map[string]processor.Config{}, 155 Outputs: map[string]output.Config{}, 156 Caches: map[string]cache.Config{}, 157 RateLimits: map[string]ratelimit.Config{}, 158 Plugins: map[string]PluginConfig{}, 159 } 160 } 161 162 // AddFrom takes another Config and adds all of its resources to itself. If 163 // there are any resource name collisions an error is returned. 164 func (c *Config) AddFrom(extra *Config) error { 165 for k, v := range extra.Inputs { 166 if _, exists := c.Inputs[k]; exists { 167 return fmt.Errorf("resource input name collision: %v", k) 168 } 169 c.Inputs[k] = v 170 } 171 for k, v := range extra.Conditions { 172 if _, exists := c.Conditions[k]; exists { 173 return fmt.Errorf("resource condition name collision: %v", k) 174 } 175 c.Conditions[k] = v 176 } 177 for k, v := range extra.Processors { 178 if _, exists := c.Processors[k]; exists { 179 return fmt.Errorf("resource processor name collision: %v", k) 180 } 181 c.Processors[k] = v 182 } 183 for k, v := range extra.Outputs { 184 if _, exists := c.Outputs[k]; exists { 185 return fmt.Errorf("resource output name collision: %v", k) 186 } 187 c.Outputs[k] = v 188 } 189 for k, v := range extra.Caches { 190 if _, exists := c.Caches[k]; exists { 191 return fmt.Errorf("resource cache name collision: %v", k) 192 } 193 c.Caches[k] = v 194 } 195 for k, v := range extra.RateLimits { 196 if _, exists := c.RateLimits[k]; exists { 197 return fmt.Errorf("resource ratelimit name collision: %v", k) 198 } 199 c.RateLimits[k] = v 200 } 201 for k, v := range extra.Plugins { 202 if _, exists := c.Plugins[k]; exists { 203 return fmt.Errorf("resource plugin name collision: %v", k) 204 } 205 c.Plugins[k] = v 206 } 207 return nil 208 } 209 210 // AddExamples inserts example caches and conditions if none exist in the 211 // config. 212 func AddExamples(c *Config) { 213 if len(c.Inputs) == 0 { 214 c.Inputs["example"] = input.NewConfig() 215 } 216 if len(c.Conditions) == 0 { 217 c.Conditions["example"] = condition.NewConfig() 218 } 219 if len(c.Processors) == 0 { 220 c.Processors["example"] = processor.NewConfig() 221 } 222 if len(c.Outputs) == 0 { 223 c.Outputs["example"] = output.NewConfig() 224 } 225 if len(c.Caches) == 0 { 226 c.Caches["example"] = cache.NewConfig() 227 } 228 if len(c.RateLimits) == 0 { 229 c.RateLimits["example"] = ratelimit.NewConfig() 230 } 231 } 232 233 //------------------------------------------------------------------------------ 234 235 // SanitiseConfig creates a sanitised version of a manager config. 236 func SanitiseConfig(conf Config) (interface{}, error) { 237 return conf.Sanitised(false) 238 } 239 240 // Sanitised returns a sanitised version of the config, meaning sections that 241 // aren't relevant to behaviour are removed. Also optionally removes deprecated 242 // fields. 243 func (c Config) Sanitised(removeDeprecated bool) (interface{}, error) { 244 var err error 245 246 inputs := map[string]interface{}{} 247 for k, v := range c.Inputs { 248 if inputs[k], err = v.Sanitised(removeDeprecated); err != nil { 249 return nil, err 250 } 251 } 252 253 caches := map[string]interface{}{} 254 for k, v := range c.Caches { 255 if caches[k], err = v.Sanitised(removeDeprecated); err != nil { 256 return nil, err 257 } 258 } 259 260 conditions := map[string]interface{}{} 261 for k, v := range c.Conditions { 262 if conditions[k], err = v.Sanitised(removeDeprecated); err != nil { 263 return nil, err 264 } 265 } 266 267 processors := map[string]interface{}{} 268 for k, v := range c.Processors { 269 if processors[k], err = v.Sanitised(removeDeprecated); err != nil { 270 return nil, err 271 } 272 } 273 274 outputs := map[string]interface{}{} 275 for k, v := range c.Outputs { 276 if outputs[k], err = v.Sanitised(removeDeprecated); err != nil { 277 return nil, err 278 } 279 } 280 281 rateLimits := map[string]interface{}{} 282 for k, v := range c.RateLimits { 283 if rateLimits[k], err = v.Sanitised(removeDeprecated); err != nil { 284 return nil, err 285 } 286 } 287 288 plugins := map[string]interface{}{} 289 for k, v := range c.Plugins { 290 if spec, exists := pluginSpecs[v.Type]; exists { 291 if spec.confSanitiser != nil { 292 outputMap := config.Sanitised{} 293 outputMap["type"] = v.Type 294 outputMap["plugin"] = spec.confSanitiser(v.Plugin) 295 plugins[k] = outputMap 296 } else { 297 plugins[k] = v 298 } 299 } 300 } 301 302 m := map[string]interface{}{ 303 "inputs": inputs, 304 "conditions": conditions, 305 "processors": processors, 306 "outputs": outputs, 307 "caches": caches, 308 "rate_limits": rateLimits, 309 } 310 if len(plugins) > 0 { 311 m["plugins"] = plugins 312 } 313 return m, nil 314 }