1package collectd
2
3import (
4	"errors"
5	"time"
6
7	"github.com/influxdata/influxdb/monitor/diagnostics"
8	"github.com/influxdata/influxdb/toml"
9)
10
11const (
12	// DefaultBindAddress is the default port to bind to.
13	DefaultBindAddress = ":25826"
14
15	// DefaultDatabase is the default DB to write to.
16	DefaultDatabase = "collectd"
17
18	// DefaultRetentionPolicy is the default retention policy of the writes.
19	DefaultRetentionPolicy = ""
20
21	// DefaultBatchSize is the default write batch size.
22	DefaultBatchSize = 5000
23
24	// DefaultBatchPending is the default number of pending write batches.
25	DefaultBatchPending = 10
26
27	// DefaultBatchDuration is the default batch timeout duration.
28	DefaultBatchDuration = toml.Duration(10 * time.Second)
29
30	// DefaultTypesDB is the default location of the collectd types db file.
31	DefaultTypesDB = "/usr/share/collectd/types.db"
32
33	// DefaultReadBuffer is the default buffer size for the UDP listener.
34	// Sets the size of the operating system's receive buffer associated with
35	// the UDP traffic. Keep in mind that the OS must be able
36	// to handle the number set here or the UDP listener will error and exit.
37	//
38	// DefaultReadBuffer = 0 means to use the OS default, which is usually too
39	// small for high UDP performance.
40	//
41	// Increasing OS buffer limits:
42	//     Linux:      sudo sysctl -w net.core.rmem_max=<read-buffer>
43	//     BSD/Darwin: sudo sysctl -w kern.ipc.maxsockbuf=<read-buffer>
44	DefaultReadBuffer = 0
45
46	// DefaultSecurityLevel is the default security level.
47	DefaultSecurityLevel = "none"
48
49	// DefaultAuthFile is the default location of the user/password file.
50	DefaultAuthFile = "/etc/collectd/auth_file"
51
52	// DefaultParseMultiValuePlugin is "split", defaulting to version <1.2 where plugin values were split into separate rows
53	DefaultParseMultiValuePlugin = "split"
54)
55
56// Config represents a configuration for the collectd service.
57type Config struct {
58	Enabled               bool          `toml:"enabled"`
59	BindAddress           string        `toml:"bind-address"`
60	Database              string        `toml:"database"`
61	RetentionPolicy       string        `toml:"retention-policy"`
62	BatchSize             int           `toml:"batch-size"`
63	BatchPending          int           `toml:"batch-pending"`
64	BatchDuration         toml.Duration `toml:"batch-timeout"`
65	ReadBuffer            int           `toml:"read-buffer"`
66	TypesDB               string        `toml:"typesdb"`
67	SecurityLevel         string        `toml:"security-level"`
68	AuthFile              string        `toml:"auth-file"`
69	ParseMultiValuePlugin string        `toml:"parse-multivalue-plugin"`
70}
71
72// NewConfig returns a new instance of Config with defaults.
73func NewConfig() Config {
74	return Config{
75		BindAddress:           DefaultBindAddress,
76		Database:              DefaultDatabase,
77		RetentionPolicy:       DefaultRetentionPolicy,
78		ReadBuffer:            DefaultReadBuffer,
79		BatchSize:             DefaultBatchSize,
80		BatchPending:          DefaultBatchPending,
81		BatchDuration:         DefaultBatchDuration,
82		TypesDB:               DefaultTypesDB,
83		SecurityLevel:         DefaultSecurityLevel,
84		AuthFile:              DefaultAuthFile,
85		ParseMultiValuePlugin: DefaultParseMultiValuePlugin,
86	}
87}
88
89// WithDefaults takes the given config and returns a new config with any required
90// default values set.
91func (c *Config) WithDefaults() *Config {
92	d := *c
93	if d.BindAddress == "" {
94		d.BindAddress = DefaultBindAddress
95	}
96	if d.Database == "" {
97		d.Database = DefaultDatabase
98	}
99	if d.RetentionPolicy == "" {
100		d.RetentionPolicy = DefaultRetentionPolicy
101	}
102	if d.BatchSize == 0 {
103		d.BatchSize = DefaultBatchSize
104	}
105	if d.BatchPending == 0 {
106		d.BatchPending = DefaultBatchPending
107	}
108	if d.BatchDuration == 0 {
109		d.BatchDuration = DefaultBatchDuration
110	}
111	if d.ReadBuffer == 0 {
112		d.ReadBuffer = DefaultReadBuffer
113	}
114	if d.TypesDB == "" {
115		d.TypesDB = DefaultTypesDB
116	}
117	if d.SecurityLevel == "" {
118		d.SecurityLevel = DefaultSecurityLevel
119	}
120	if d.AuthFile == "" {
121		d.AuthFile = DefaultAuthFile
122	}
123	if d.ParseMultiValuePlugin == "" {
124		d.ParseMultiValuePlugin = DefaultParseMultiValuePlugin
125	}
126
127	return &d
128}
129
130// Validate returns an error if the Config is invalid.
131func (c *Config) Validate() error {
132	switch c.SecurityLevel {
133	case "none", "sign", "encrypt":
134	default:
135		return errors.New("Invalid security level")
136	}
137
138	switch c.ParseMultiValuePlugin {
139	case "split", "join":
140	default:
141		return errors.New(`Invalid value for parse-multivalue-plugin. Valid options are "split" and "join"`)
142	}
143
144	return nil
145}
146
147// Configs wraps a slice of Config to aggregate diagnostics.
148type Configs []Config
149
150// Diagnostics returns one set of diagnostics for all of the Configs.
151func (c Configs) Diagnostics() (*diagnostics.Diagnostics, error) {
152	d := &diagnostics.Diagnostics{
153		Columns: []string{"enabled", "bind-address", "database", "retention-policy", "batch-size", "batch-pending", "batch-timeout"},
154	}
155
156	for _, cc := range c {
157		if !cc.Enabled {
158			d.AddRow([]interface{}{false})
159			continue
160		}
161
162		r := []interface{}{true, cc.BindAddress, cc.Database, cc.RetentionPolicy, cc.BatchSize, cc.BatchPending, cc.BatchDuration}
163		d.AddRow(r)
164	}
165
166	return d, nil
167}
168
169// Enabled returns true if any underlying Config is Enabled.
170func (c Configs) Enabled() bool {
171	for _, cc := range c {
172		if cc.Enabled {
173			return true
174		}
175	}
176	return false
177}
178