github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"sync"
    12  	"sync/atomic"
    13  
    14  	"github.com/kelseyhightower/envconfig"
    15  
    16  	"github.com/TykTechnologies/tyk/apidef"
    17  	logger "github.com/TykTechnologies/tyk/log"
    18  	"github.com/TykTechnologies/tyk/regexp"
    19  )
    20  
    21  type IPsHandleStrategy string
    22  
    23  var (
    24  	log      = logger.Get()
    25  	global   atomic.Value
    26  	globalMu sync.Mutex
    27  
    28  	Default = Config{
    29  		ListenPort:     8080,
    30  		Secret:         "352d20ee67be67f6340b4c0605b044b7",
    31  		TemplatePath:   "templates",
    32  		MiddlewarePath: "middleware",
    33  		AppPath:        "apps/",
    34  		Storage: StorageOptionsConf{
    35  			Type:    "redis",
    36  			Host:    "localhost",
    37  			MaxIdle: 100,
    38  			Port:    6379,
    39  		},
    40  		AnalyticsConfig: AnalyticsConfigConfig{
    41  			IgnoredIPs: make([]string, 0),
    42  		},
    43  		DnsCache: DnsCacheConfig{
    44  			Enabled:                   false,
    45  			TTL:                       dnsCacheDefaultTtl,
    46  			CheckInterval:             dnsCacheDefaultCheckInterval,
    47  			MultipleIPsHandleStrategy: NoCacheStrategy,
    48  		},
    49  	}
    50  )
    51  
    52  const (
    53  	envPrefix = "TYK_GW"
    54  
    55  	dnsCacheDefaultTtl           = 3600
    56  	dnsCacheDefaultCheckInterval = 60
    57  
    58  	PickFirstStrategy IPsHandleStrategy = "pick_first"
    59  	RandomStrategy    IPsHandleStrategy = "random"
    60  	NoCacheStrategy   IPsHandleStrategy = "no_cache"
    61  
    62  	DefaultDashPolicySource     = "service"
    63  	DefaultDashPolicyRecordName = "tyk_policies"
    64  )
    65  
    66  type PoliciesConfig struct {
    67  	PolicySource           string `json:"policy_source"`
    68  	PolicyConnectionString string `json:"policy_connection_string"`
    69  	PolicyRecordName       string `json:"policy_record_name"`
    70  	AllowExplicitPolicyID  bool   `json:"allow_explicit_policy_id"`
    71  }
    72  
    73  type DBAppConfOptionsConfig struct {
    74  	ConnectionString string   `json:"connection_string"`
    75  	NodeIsSegmented  bool     `json:"node_is_segmented"`
    76  	Tags             []string `json:"tags"`
    77  }
    78  
    79  type RedisDBAppConfOptionsConfig struct {
    80  	Host     string `json:"host"`
    81  	Port     int    `json:"port"`
    82  	DB       int    `json:"db"`
    83  	Password string `json:"password"`
    84  	PoolSize int    `json:"pool_size"`
    85  }
    86  
    87  type StorageOptionsConf struct {
    88  	Type                  string            `json:"type"`
    89  	Host                  string            `json:"host"`
    90  	Port                  int               `json:"port"`
    91  	Hosts                 map[string]string `json:"hosts"`
    92  	Username              string            `json:"username"`
    93  	Password              string            `json:"password"`
    94  	Database              int               `json:"database"`
    95  	MaxIdle               int               `json:"optimisation_max_idle"`
    96  	MaxActive             int               `json:"optimisation_max_active"`
    97  	Timeout               int               `json:"timeout"`
    98  	EnableCluster         bool              `json:"enable_cluster"`
    99  	UseSSL                bool              `json:"use_ssl"`
   100  	SSLInsecureSkipVerify bool              `json:"ssl_insecure_skip_verify"`
   101  }
   102  
   103  type NormalisedURLConfig struct {
   104  	Enabled            bool                 `json:"enabled"`
   105  	NormaliseUUIDs     bool                 `json:"normalise_uuids"`
   106  	NormaliseNumbers   bool                 `json:"normalise_numbers"`
   107  	Custom             []string             `json:"custom_patterns"`
   108  	CompiledPatternSet NormaliseURLPatterns `json:"-"` // see analytics.go
   109  }
   110  
   111  type NormaliseURLPatterns struct {
   112  	UUIDs  *regexp.Regexp
   113  	IDs    *regexp.Regexp
   114  	Custom []*regexp.Regexp
   115  }
   116  
   117  type AnalyticsConfigConfig struct {
   118  	Type                    string              `json:"type"`
   119  	IgnoredIPs              []string            `json:"ignored_ips"`
   120  	EnableDetailedRecording bool                `json:"enable_detailed_recording"`
   121  	EnableGeoIP             bool                `json:"enable_geo_ip"`
   122  	GeoIPDBLocation         string              `json:"geo_ip_db_path"`
   123  	NormaliseUrls           NormalisedURLConfig `json:"normalise_urls"`
   124  	PoolSize                int                 `json:"pool_size"`
   125  	RecordsBufferSize       uint64              `json:"records_buffer_size"`
   126  	StorageExpirationTime   int                 `json:"storage_expiration_time"`
   127  	ignoredIPsCompiled      map[string]bool
   128  }
   129  
   130  type HealthCheckConfig struct {
   131  	EnableHealthChecks      bool  `json:"enable_health_checks"`
   132  	HealthCheckValueTimeout int64 `json:"health_check_value_timeouts"`
   133  }
   134  
   135  type DnsCacheConfig struct {
   136  	Enabled                   bool              `json:"enabled"`
   137  	TTL                       int64             `json:"ttl"`
   138  	CheckInterval             int64             `json:"-" ignored:"true"` //controls cache cleanup interval. By convention shouldn't be exposed to config or env_variable_setup
   139  	MultipleIPsHandleStrategy IPsHandleStrategy `json:"multiple_ips_handle_strategy"`
   140  }
   141  
   142  type MonitorConfig struct {
   143  	EnableTriggerMonitors bool               `json:"enable_trigger_monitors"`
   144  	Config                WebHookHandlerConf `json:"configuration"`
   145  	GlobalTriggerLimit    float64            `json:"global_trigger_limit"`
   146  	MonitorUserKeys       bool               `json:"monitor_user_keys"`
   147  	MonitorOrgKeys        bool               `json:"monitor_org_keys"`
   148  }
   149  
   150  type WebHookHandlerConf struct {
   151  	Method       string            `bson:"method" json:"method"`
   152  	TargetPath   string            `bson:"target_path" json:"target_path"`
   153  	TemplatePath string            `bson:"template_path" json:"template_path"`
   154  	HeaderList   map[string]string `bson:"header_map" json:"header_map"`
   155  	EventTimeout int64             `bson:"event_timeout" json:"event_timeout"`
   156  }
   157  
   158  type SlaveOptionsConfig struct {
   159  	UseRPC                          bool   `json:"use_rpc"`
   160  	UseSSL                          bool   `json:"use_ssl"`
   161  	SSLInsecureSkipVerify           bool   `json:"ssl_insecure_skip_verify"`
   162  	ConnectionString                string `json:"connection_string"`
   163  	RPCKey                          string `json:"rpc_key"`
   164  	APIKey                          string `json:"api_key"`
   165  	EnableRPCCache                  bool   `json:"enable_rpc_cache"`
   166  	BindToSlugsInsteadOfListenPaths bool   `json:"bind_to_slugs"`
   167  	DisableKeySpaceSync             bool   `json:"disable_keyspace_sync"`
   168  	GroupID                         string `json:"group_id"`
   169  	CallTimeout                     int    `json:"call_timeout"`
   170  	PingTimeout                     int    `json:"ping_timeout"`
   171  	RPCPoolSize                     int    `json:"rpc_pool_size"`
   172  }
   173  
   174  type LocalSessionCacheConf struct {
   175  	DisableCacheSessionState bool `json:"disable_cached_session_state"`
   176  	CachedSessionTimeout     int  `json:"cached_session_timeout"`
   177  	CacheSessionEviction     int  `json:"cached_session_eviction"`
   178  }
   179  
   180  type HttpServerOptionsConfig struct {
   181  	OverrideDefaults       bool       `json:"override_defaults"`
   182  	ReadTimeout            int        `json:"read_timeout"`
   183  	WriteTimeout           int        `json:"write_timeout"`
   184  	UseSSL                 bool       `json:"use_ssl"`
   185  	UseLE_SSL              bool       `json:"use_ssl_le"`
   186  	EnableHttp2            bool       `json:"enable_http2"`
   187  	SSLInsecureSkipVerify  bool       `json:"ssl_insecure_skip_verify"`
   188  	EnableWebSockets       bool       `json:"enable_websockets"`
   189  	Certificates           []CertData `json:"certificates"`
   190  	SSLCertificates        []string   `json:"ssl_certificates"`
   191  	ServerName             string     `json:"server_name"`
   192  	MinVersion             uint16     `json:"min_version"`
   193  	FlushInterval          int        `json:"flush_interval"`
   194  	SkipURLCleaning        bool       `json:"skip_url_cleaning"`
   195  	SkipTargetPathEscaping bool       `json:"skip_target_path_escaping"`
   196  	Ciphers                []string   `json:"ssl_ciphers"`
   197  }
   198  
   199  type AuthOverrideConf struct {
   200  	ForceAuthProvider    bool                       `json:"force_auth_provider"`
   201  	AuthProvider         apidef.AuthProviderMeta    `json:"auth_provider"`
   202  	ForceSessionProvider bool                       `json:"force_session_provider"`
   203  	SessionProvider      apidef.SessionProviderMeta `json:"session_provider"`
   204  }
   205  
   206  type UptimeTestsConfigDetail struct {
   207  	FailureTriggerSampleSize int  `json:"failure_trigger_sample_size"`
   208  	TimeWait                 int  `json:"time_wait"`
   209  	CheckerPoolSize          int  `json:"checker_pool_size"`
   210  	EnableUptimeAnalytics    bool `json:"enable_uptime_analytics"`
   211  }
   212  
   213  type UptimeTestsConfig struct {
   214  	Disable bool                    `json:"disable"`
   215  	Config  UptimeTestsConfigDetail `json:"config"`
   216  }
   217  
   218  type ServiceDiscoveryConf struct {
   219  	DefaultCacheTimeout int `json:"default_cache_timeout"`
   220  }
   221  
   222  type CoProcessConfig struct {
   223  	EnableCoProcess     bool   `json:"enable_coprocess"`
   224  	CoProcessGRPCServer string `json:"coprocess_grpc_server"`
   225  	PythonPathPrefix    string `json:"python_path_prefix"`
   226  }
   227  
   228  type CertificatesConfig struct {
   229  	API        []string          `json:"apis"`
   230  	Upstream   map[string]string `json:"upstream"`
   231  	ControlAPI []string          `json:"control_api"`
   232  	Dashboard  []string          `json:"dashboard_api"`
   233  	MDCB       []string          `json:"mdcb_api"`
   234  }
   235  
   236  type SecurityConfig struct {
   237  	PrivateCertificateEncodingSecret string             `json:"private_certificate_encoding_secret"`
   238  	ControlAPIUseMutualTLS           bool               `json:"control_api_use_mutual_tls"`
   239  	PinnedPublicKeys                 map[string]string  `json:"pinned_public_keys"`
   240  	Certificates                     CertificatesConfig `json:"certificates"`
   241  }
   242  
   243  type NewRelicConfig struct {
   244  	AppName    string `json:"app_name"`
   245  	LicenseKey string `json:"license_key"`
   246  }
   247  
   248  type Tracer struct {
   249  	// The name of the tracer to initialize. For instance appdash, to use appdash
   250  	// tracer
   251  	Name string `json:"name"`
   252  
   253  	// If true then this tracer will be activated and all tracing data will be sent
   254  	// to this tracer.NoOp tracer is used otherwise which collects traces but
   255  	// discard them.
   256  	Enabled bool `json:"enabled"`
   257  
   258  	// Key value pairs used to initialize the tracer. These are tracer specific,
   259  	// each tracer requires different options to operate. Please see trace package
   260  	// for options required by supported tracer implementation.
   261  	Options map[string]interface{} `json:"options"`
   262  }
   263  
   264  // Config is the configuration object used by tyk to set up various parameters.
   265  type Config struct {
   266  	// OriginalPath is the path to the config file that was read. If
   267  	// none was found, it's the path to the default config file that
   268  	// was written.
   269  	OriginalPath string `json:"-"`
   270  
   271  	HostName                  string                  `json:"hostname"`
   272  	ListenAddress             string                  `json:"listen_address"`
   273  	ListenPort                int                     `json:"listen_port"`
   274  	ControlAPIHostname        string                  `json:"control_api_hostname"`
   275  	ControlAPIPort            int                     `json:"control_api_port"`
   276  	Secret                    string                  `json:"secret"`
   277  	NodeSecret                string                  `json:"node_secret"`
   278  	PIDFileLocation           string                  `json:"pid_file_location"`
   279  	AllowInsecureConfigs      bool                    `json:"allow_insecure_configs"`
   280  	PublicKeyPath             string                  `json:"public_key_path"`
   281  	AllowRemoteConfig         bool                    `bson:"allow_remote_config" json:"allow_remote_config"`
   282  	Security                  SecurityConfig          `json:"security"`
   283  	HttpServerOptions         HttpServerOptionsConfig `json:"http_server_options"`
   284  	ReloadWaitTime            int                     `bson:"reload_wait_time" json:"reload_wait_time"`
   285  	VersionHeader             string                  `json:"version_header"`
   286  	UseAsyncSessionWrite      bool                    `json:"optimisations_use_async_session_write"`
   287  	SuppressRedisSignalReload bool                    `json:"suppress_redis_signal_reload"`
   288  
   289  	// Gateway Security Policies
   290  	HashKeys                bool           `json:"hash_keys"`
   291  	HashKeyFunction         string         `json:"hash_key_function"`
   292  	EnableHashedKeysListing bool           `json:"enable_hashed_keys_listing"`
   293  	MinTokenLength          int            `json:"min_token_length"`
   294  	EnableAPISegregation    bool           `json:"enable_api_segregation"`
   295  	TemplatePath            string         `json:"template_path"`
   296  	Policies                PoliciesConfig `json:"policies"`
   297  
   298  	// CE Configurations
   299  	AppPath string `json:"app_path"`
   300  
   301  	// Dashboard Configurations
   302  	UseDBAppConfigs          bool                   `json:"use_db_app_configs"`
   303  	DBAppConfOptions         DBAppConfOptionsConfig `json:"db_app_conf_options"`
   304  	Storage                  StorageOptionsConf     `json:"storage"`
   305  	DisableDashboardZeroConf bool                   `json:"disable_dashboard_zeroconf"`
   306  
   307  	// Slave Configurations
   308  	SlaveOptions   SlaveOptionsConfig `json:"slave_options"`
   309  	ManagementNode bool               `json:"management_node"`
   310  	AuthOverride   AuthOverrideConf   `json:"auth_override"`
   311  
   312  	// Rate Limiting Strategy
   313  	EnableNonTransactionalRateLimiter bool `json:"enable_non_transactional_rate_limiter"`
   314  	EnableSentinelRateLimiter         bool `json:"enable_sentinel_rate_limiter"`
   315  	EnableRedisRollingLimiter         bool `json:"enable_redis_rolling_limiter"`
   316  	DRLNotificationFrequency          int  `json:"drl_notification_frequency"`
   317  
   318  	// Organization configurations
   319  	EnforceOrgDataAge               bool          `json:"enforce_org_data_age"`
   320  	EnforceOrgDataDetailLogging     bool          `json:"enforce_org_data_detail_logging"`
   321  	EnforceOrgQuotas                bool          `json:"enforce_org_quotas"`
   322  	ExperimentalProcessOrgOffThread bool          `json:"experimental_process_org_off_thread"`
   323  	Monitor                         MonitorConfig `json:"monitor"`
   324  
   325  	// Client-Gateway Configuration
   326  	MaxIdleConns         int   `bson:"max_idle_connections" json:"max_idle_connections"`
   327  	MaxIdleConnsPerHost  int   `bson:"max_idle_connections_per_host" json:"max_idle_connections_per_host"`
   328  	MaxConnTime          int64 `json:"max_conn_time"`
   329  	CloseIdleConnections bool  `json:"close_idle_connections"`
   330  	CloseConnections     bool  `json:"close_connections"`
   331  	EnableCustomDomains  bool  `json:"enable_custom_domains"`
   332  	// If AllowMasterKeys is set to true, session objects (key definitions) that do not have explicit access rights set
   333  	// will be allowed by Tyk. This means that keys that are created have access to ALL APIs, which in many cases is
   334  	// unwanted behaviour unless you are sure about what you are doing.
   335  	AllowMasterKeys bool `json:"allow_master_keys"`
   336  
   337  	// Gateway-Service Configuration
   338  	ServiceDiscovery              ServiceDiscoveryConf `json:"service_discovery"`
   339  	ProxySSLInsecureSkipVerify    bool                 `json:"proxy_ssl_insecure_skip_verify"`
   340  	ProxyEnableHttp2              bool                 `json:"proxy_enable_http2"`
   341  	ProxySSLMinVersion            uint16               `json:"proxy_ssl_min_version"`
   342  	ProxySSLCipherSuites          []string             `json:"proxy_ssl_ciphers"`
   343  	ProxyDefaultTimeout           float64              `json:"proxy_default_timeout"`
   344  	ProxySSLDisableRenegotiation  bool                 `json:"proxy_ssl_disable_renegotiation"`
   345  	ProxyCloseConnections         bool                 `json:"proxy_close_connections"`
   346  	UptimeTests                   UptimeTestsConfig    `json:"uptime_tests"`
   347  	HealthCheck                   HealthCheckConfig    `json:"health_check"`
   348  	OauthRefreshExpire            int64                `json:"oauth_refresh_token_expire"`
   349  	OauthTokenExpire              int32                `json:"oauth_token_expire"`
   350  	OauthTokenExpiredRetainPeriod int32                `json:"oauth_token_expired_retain_period"`
   351  	OauthRedirectUriSeparator     string               `json:"oauth_redirect_uri_separator"`
   352  	EnableKeyLogging              bool                 `json:"enable_key_logging"`
   353  
   354  	// Proxy analytics configuration
   355  	EnableAnalytics bool                  `json:"enable_analytics"`
   356  	AnalyticsConfig AnalyticsConfigConfig `json:"analytics_config"`
   357  
   358  	// Cache
   359  	DnsCache                 DnsCacheConfig        `json:"dns_cache"`
   360  	DisableRegexpCache       bool                  `json:"disable_regexp_cache"`
   361  	RegexpCacheExpire        int32                 `json:"regexp_cache_expire"`
   362  	LocalSessionCache        LocalSessionCacheConf `json:"local_session_cache"`
   363  	EnableSeperateCacheStore bool                  `json:"enable_separate_cache_store"`
   364  	CacheStorage             StorageOptionsConf    `json:"cache_storage"`
   365  
   366  	// Middleware/Plugin Configuration
   367  	EnableBundleDownloader  bool            `bson:"enable_bundle_downloader" json:"enable_bundle_downloader"`
   368  	BundleBaseURL           string          `bson:"bundle_base_url" json:"bundle_base_url"`
   369  	EnableJSVM              bool            `json:"enable_jsvm"`
   370  	JSVMTimeout             int             `json:"jsvm_timeout"`
   371  	DisableVirtualPathBlobs bool            `json:"disable_virtual_path_blobs"`
   372  	TykJSPath               string          `json:"tyk_js_path"`
   373  	MiddlewarePath          string          `json:"middleware_path"`
   374  	CoProcessOptions        CoProcessConfig `json:"coprocess_options"`
   375  
   376  	// Monitoring, Logging & Profiling
   377  	LogLevel                string         `json:"log_level"`
   378  	HealthCheckEndpointName string         `json:"health_check_endpoint_name"`
   379  	Tracer                  Tracer         `json:"tracing"`
   380  	NewRelic                NewRelicConfig `json:"newrelic"`
   381  	HTTPProfile             bool           `json:"enable_http_profiler"`
   382  	UseRedisLog             bool           `json:"use_redis_log"`
   383  	SentryCode              string         `json:"sentry_code"`
   384  	UseSentry               bool           `json:"use_sentry"`
   385  	UseSyslog               bool           `json:"use_syslog"`
   386  	UseGraylog              bool           `json:"use_graylog"`
   387  	UseLogstash             bool           `json:"use_logstash"`
   388  	GraylogNetworkAddr      string         `json:"graylog_network_addr"`
   389  	LogstashNetworkAddr     string         `json:"logstash_network_addr"`
   390  	SyslogTransport         string         `json:"syslog_transport"`
   391  	LogstashTransport       string         `json:"logstash_transport"`
   392  	SyslogNetworkAddr       string         `json:"syslog_network_addr"`
   393  	StatsdConnectionString  string         `json:"statsd_connection_string"`
   394  	StatsdPrefix            string         `json:"statsd_prefix"`
   395  
   396  	// Event System
   397  	EventHandlers        apidef.EventHandlerMetaConfig         `json:"event_handlers"`
   398  	EventTriggers        map[apidef.TykEvent][]TykEventHandler `json:"event_trigers_defunct"`  // Deprecated: Config.GetEventTriggers instead.
   399  	EventTriggersDefunct map[apidef.TykEvent][]TykEventHandler `json:"event_triggers_defunct"` // Deprecated: Config.GetEventTriggers instead.
   400  
   401  	// TODO: These config options are not documented - What do they do?
   402  	SessionUpdatePoolSize          int   `json:"session_update_pool_size"`
   403  	SessionUpdateBufferSize        int   `json:"session_update_buffer_size"`
   404  	SupressDefaultOrgStore         bool  `json:"suppress_default_org_store"`
   405  	LegacyEnableAllowanceCountdown bool  `bson:"legacy_enable_allowance_countdown" json:"legacy_enable_allowance_countdown"`
   406  	GlobalSessionLifetime          int64 `bson:"global_session_lifetime" json:"global_session_lifetime"`
   407  	ForceGlobalSessionLifetime     bool  `bson:"force_global_session_lifetime" json:"force_global_session_lifetime"`
   408  	HideGeneratorHeader            bool  `json:"hide_generator_header"`
   409  
   410  	// Cisco - Redis DB Api Store
   411  	UseRedisDBAppConfig   bool                        `json:"use_redis_db_app_configs"`
   412  	RedisDBAppConfOptions RedisDBAppConfOptionsConfig `json:"redis_db_app_conf_options"`
   413  
   414  	// Cisco - Read timeout
   415  	DynamicAPIConnTimeout int `json:"dynamic_api_timeout_milli_sec"`
   416  }
   417  
   418  // GetEventTriggers returns event triggers. There was a typo in the json tag.
   419  // To maintain backward compatibility, this solution is chosen.
   420  func (c Config) GetEventTriggers() map[apidef.TykEvent][]TykEventHandler {
   421  	if c.EventTriggersDefunct == nil {
   422  		return c.EventTriggers
   423  	}
   424  
   425  	if c.EventTriggers != nil {
   426  		log.Info("Both event_trigers_defunct and event_triggers_defunct are configured in the config," +
   427  			" event_triggers_defunct will be used.")
   428  	}
   429  
   430  	return c.EventTriggersDefunct
   431  }
   432  
   433  func (c *Config) SetEventTriggers(eventTriggers map[apidef.TykEvent][]TykEventHandler) {
   434  	c.EventTriggersDefunct = eventTriggers
   435  }
   436  
   437  type CertData struct {
   438  	Name     string `json:"domain_name"`
   439  	CertFile string `json:"cert_file"`
   440  	KeyFile  string `json:"key_file"`
   441  }
   442  
   443  // EventMessage is a standard form to send event data to handlers
   444  type EventMessage struct {
   445  	Type      apidef.TykEvent
   446  	Meta      interface{}
   447  	TimeStamp string
   448  }
   449  
   450  // TykEventHandler defines an event handler, e.g. LogMessageEventHandler will handle an event by logging it to stdout.
   451  type TykEventHandler interface {
   452  	Init(interface{}) error
   453  	HandleEvent(EventMessage)
   454  }
   455  
   456  func init() {
   457  	SetGlobal(Config{})
   458  }
   459  
   460  func Global() Config {
   461  	return global.Load().(Config)
   462  }
   463  
   464  func SetGlobal(conf Config) {
   465  	globalMu.Lock()
   466  	defer globalMu.Unlock()
   467  	global.Store(conf)
   468  }
   469  
   470  func WriteConf(path string, conf *Config) error {
   471  	bs, err := json.MarshalIndent(conf, "", "    ")
   472  	if err != nil {
   473  		return err
   474  	}
   475  	return ioutil.WriteFile(path, bs, 0644)
   476  }
   477  
   478  // writeDefault will set conf to the default config and write it to disk
   479  // in path, if the path is non-empty.
   480  func WriteDefault(path string, conf *Config) error {
   481  	_, b, _, _ := runtime.Caller(0)
   482  	configPath := filepath.Dir(b)
   483  	rootPath := filepath.Dir(configPath)
   484  	Default.TemplatePath = filepath.Join(rootPath, "templates")
   485  
   486  	*conf = Default
   487  	if err := envconfig.Process(envPrefix, conf); err != nil {
   488  		return err
   489  	}
   490  	if path == "" {
   491  		return nil
   492  	}
   493  	return WriteConf(path, conf)
   494  }
   495  
   496  // Load will load a configuration file, trying each of the paths given
   497  // and using the first one that is a regular file and can be opened.
   498  //
   499  // If none exists, a default config will be written to the first path in
   500  // the list.
   501  //
   502  // An error will be returned only if any of the paths existed but was
   503  // not a valid config file.
   504  func Load(paths []string, conf *Config) error {
   505  	var r io.Reader
   506  	for _, path := range paths {
   507  		f, err := os.Open(path)
   508  		if err == nil {
   509  			r = f
   510  			conf.OriginalPath = path
   511  			break
   512  		}
   513  		if os.IsNotExist(err) {
   514  			continue
   515  		}
   516  		return err
   517  	}
   518  	if r == nil {
   519  		path := paths[0]
   520  		log.Warnf("No config file found, writing default to %s", path)
   521  		if err := WriteDefault(path, conf); err != nil {
   522  			return err
   523  		}
   524  		log.Info("Loading default configuration...")
   525  		return Load([]string{path}, conf)
   526  	}
   527  	if err := json.NewDecoder(r).Decode(&conf); err != nil {
   528  		return fmt.Errorf("couldn't unmarshal config: %v", err)
   529  	}
   530  	if err := envconfig.Process(envPrefix, conf); err != nil {
   531  		return fmt.Errorf("failed to process config env vars: %v", err)
   532  	}
   533  	return nil
   534  }
   535  
   536  func (c *Config) LoadIgnoredIPs() {
   537  	c.AnalyticsConfig.ignoredIPsCompiled = make(map[string]bool, len(c.AnalyticsConfig.IgnoredIPs))
   538  	for _, ip := range c.AnalyticsConfig.IgnoredIPs {
   539  		c.AnalyticsConfig.ignoredIPsCompiled[ip] = true
   540  	}
   541  }
   542  
   543  func (c *Config) StoreAnalytics(ip string) bool {
   544  	if !c.EnableAnalytics {
   545  		return false
   546  	}
   547  
   548  	return !c.AnalyticsConfig.ignoredIPsCompiled[ip]
   549  }