github.com/thanos-io/thanos@v0.32.5/scripts/cfggen/main.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package main 5 6 import ( 7 "fmt" 8 "io" 9 "os" 10 "path/filepath" 11 "reflect" 12 "strings" 13 14 "github.com/fatih/structtag" 15 "github.com/go-kit/log" 16 "github.com/go-kit/log/level" 17 "github.com/pkg/errors" 18 "github.com/thanos-io/objstore/client" 19 "github.com/thanos-io/objstore/providers/azure" 20 "github.com/thanos-io/objstore/providers/bos" 21 "github.com/thanos-io/objstore/providers/cos" 22 "github.com/thanos-io/objstore/providers/filesystem" 23 "github.com/thanos-io/objstore/providers/gcs" 24 "github.com/thanos-io/objstore/providers/oss" 25 "github.com/thanos-io/objstore/providers/s3" 26 "github.com/thanos-io/objstore/providers/swift" 27 "gopkg.in/alecthomas/kingpin.v2" 28 "gopkg.in/yaml.v2" 29 30 "github.com/thanos-io/thanos/pkg/httpconfig" 31 32 "github.com/thanos-io/thanos/pkg/alert" 33 "github.com/thanos-io/thanos/pkg/cacheutil" 34 "github.com/thanos-io/thanos/pkg/logging" 35 "github.com/thanos-io/thanos/pkg/queryfrontend" 36 storecache "github.com/thanos-io/thanos/pkg/store/cache" 37 trclient "github.com/thanos-io/thanos/pkg/tracing/client" 38 "github.com/thanos-io/thanos/pkg/tracing/elasticapm" 39 "github.com/thanos-io/thanos/pkg/tracing/google_cloud" 40 "github.com/thanos-io/thanos/pkg/tracing/jaeger" 41 "github.com/thanos-io/thanos/pkg/tracing/lightstep" 42 "github.com/thanos-io/thanos/pkg/tracing/otlp" 43 ) 44 45 var ( 46 configs map[string]interface{} 47 possibleValues []string 48 49 bucketConfigs = map[client.ObjProvider]interface{}{ 50 client.AZURE: azure.Config{}, 51 client.GCS: gcs.Config{}, 52 client.S3: s3.DefaultConfig, 53 client.SWIFT: swift.DefaultConfig, 54 client.COS: cos.DefaultConfig, 55 client.ALIYUNOSS: oss.Config{}, 56 client.FILESYSTEM: filesystem.Config{}, 57 client.BOS: bos.Config{}, 58 } 59 60 tracingConfigs = map[trclient.TracingProvider]interface{}{ 61 trclient.OpenTelemetryProtocol: otlp.Config{}, 62 trclient.Jaeger: jaeger.Config{}, 63 trclient.GoogleCloud: google_cloud.Config{}, 64 trclient.ElasticAPM: elasticapm.Config{}, 65 trclient.Lightstep: lightstep.Config{}, 66 } 67 indexCacheConfigs = map[storecache.IndexCacheProvider]interface{}{ 68 storecache.INMEMORY: storecache.InMemoryIndexCacheConfig{}, 69 storecache.MEMCACHED: cacheutil.MemcachedClientConfig{}, 70 storecache.REDIS: cacheutil.DefaultRedisClientConfig, 71 } 72 73 queryfrontendCacheConfigs = map[queryfrontend.ResponseCacheProvider]interface{}{ 74 queryfrontend.INMEMORY: queryfrontend.InMemoryResponseCacheConfig{}, 75 queryfrontend.MEMCACHED: queryfrontend.MemcachedResponseCacheConfig{}, 76 queryfrontend.REDIS: queryfrontend.DefaultRedisConfig, 77 } 78 ) 79 80 func init() { 81 configs = map[string]interface{}{} 82 configs[name(logging.RequestConfig{})] = logging.RequestConfig{} 83 84 alertmgrCfg := alert.DefaultAlertmanagerConfig() 85 alertmgrCfg.EndpointsConfig.FileSDConfigs = []httpconfig.FileSDConfig{{}} 86 configs[name(alert.AlertingConfig{})] = alert.AlertingConfig{Alertmanagers: []alert.AlertmanagerConfig{alertmgrCfg}} 87 88 queryCfg := httpconfig.DefaultConfig() 89 queryCfg.EndpointsConfig.FileSDConfigs = []httpconfig.FileSDConfig{{}} 90 configs[name(httpconfig.Config{})] = []httpconfig.Config{queryCfg} 91 92 for typ, config := range bucketConfigs { 93 configs[name(config)] = client.BucketConfig{Type: typ, Config: config} 94 } 95 for typ, config := range tracingConfigs { 96 configs[name(config)] = trclient.TracingConfig{Type: typ, Config: config} 97 } 98 for typ, config := range indexCacheConfigs { 99 configs[name(config)] = storecache.IndexCacheConfig{Type: typ, Config: config} 100 } 101 for typ, config := range queryfrontendCacheConfigs { 102 configs[name(config)] = queryfrontend.CacheProviderConfig{Type: typ, Config: config} 103 } 104 105 for k := range configs { 106 possibleValues = append(possibleValues, k) 107 } 108 } 109 110 func name(typ interface{}) string { 111 return fmt.Sprintf("%T", typ) 112 } 113 114 func main() { 115 app := kingpin.New(filepath.Base(os.Args[0]), "Thanos config examples generator.") 116 app.HelpFlag.Short('h') 117 structName := app.Flag("name", fmt.Sprintf("Name of the struct to generated example for. Possible values: %v", strings.Join(possibleValues, ","))).Required().String() 118 119 errLogger := level.Error(log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))) 120 if _, err := app.Parse(os.Args[1:]); err != nil { 121 errLogger.Log("err", err) 122 os.Exit(1) 123 } 124 125 if c, ok := configs[*structName]; ok { 126 if err := generate(c, os.Stdout); err != nil { 127 errLogger.Log("err", err) 128 os.Exit(1) 129 } 130 return 131 } 132 133 errLogger.Log("err", errors.Errorf("%v struct not found. Possible values %v", *structName, strings.Join(possibleValues, ","))) 134 os.Exit(1) 135 } 136 137 func generate(obj interface{}, w io.Writer) error { 138 // We forbid omitempty option. This is for simplification for doc generation. 139 if err := checkForOmitEmptyTagOption(obj); err != nil { 140 return errors.Wrap(err, "invalid type") 141 } 142 return yaml.NewEncoder(w).Encode(obj) 143 } 144 145 func checkForOmitEmptyTagOption(obj interface{}) error { 146 return checkForOmitEmptyTagOptionRec(reflect.ValueOf(obj)) 147 } 148 149 func checkForOmitEmptyTagOptionRec(v reflect.Value) error { 150 switch v.Kind() { 151 case reflect.Struct: 152 for i := 0; i < v.NumField(); i++ { 153 tags, err := structtag.Parse(string(v.Type().Field(i).Tag)) 154 if err != nil { 155 return errors.Wrapf(err, "%s: failed to parse tag %q", v.Type().Field(i).Name, v.Type().Field(i).Tag) 156 } 157 158 tag, err := tags.Get("yaml") 159 if err != nil { 160 return errors.Wrapf(err, "%s: failed to get tag %q", v.Type().Field(i).Name, v.Type().Field(i).Tag) 161 } 162 163 for _, opts := range tag.Options { 164 if opts == "omitempty" { 165 return errors.Errorf("omitempty is forbidden for config, but spotted on field '%s'", v.Type().Field(i).Name) 166 } 167 } 168 169 if err := checkForOmitEmptyTagOptionRec(v.Field(i)); err != nil { 170 return errors.Wrapf(err, "%s", v.Type().Field(i).Name) 171 } 172 } 173 174 case reflect.Ptr: 175 return errors.New("nil pointers are not allowed in configuration") 176 177 case reflect.Interface: 178 return checkForOmitEmptyTagOptionRec(v.Elem()) 179 } 180 181 return nil 182 }