forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 9
/
import_dashboards.go
227 lines (186 loc) · 7.3 KB
/
import_dashboards.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package main
import (
"errors"
"flag"
"fmt"
"os"
"time"
lbeat "github.com/elastic/beats/libbeat/beat"
"github.com/elastic/beats/libbeat/common/fmtstr"
"github.com/elastic/beats/libbeat/dashboards/dashboards"
"github.com/elastic/beats/libbeat/outputs"
"github.com/elastic/beats/libbeat/outputs/elasticsearch"
"github.com/elastic/beats/libbeat/outputs/outil"
"github.com/elastic/beats/libbeat/outputs/transport"
)
var usage = fmt.Sprintf(`
Usage: ./import_dashboards [options]
Kibana dashboards are stored in a special index in Elasticsearch together with the searches, visualizations, and indexes that they use.
To import the official Kibana dashboards for your Beat version into a local Elasticsearch instance, use:
./import_dashboards
To import the official Kibana dashboards for your Beat version into a remote Elasticsearch instance with Shield, use:
./import_dashboards -es https://xyz.found.io -user user -pass password
For more details, check https://www.elastic.co/guide/en/beats/libbeat/5.0/import-dashboards.html.
`)
var beat string
type Options struct {
KibanaIndex string
ES string
Index string
Dir string
File string
Beat string
URL string
User string
Pass string
Certificate string
CertificateKey string
CertificateAuthority string
Insecure bool // Allow insecure SSL connections.
OnlyDashboards bool
OnlyIndex bool
Snapshot bool
Quiet bool
}
type CommandLine struct {
flagSet *flag.FlagSet
opt Options
}
type Importer struct {
cl *CommandLine
client *elasticsearch.Client
}
func DefineCommandLine() (*CommandLine, error) {
var cl CommandLine
cl.flagSet = flag.NewFlagSet("import", flag.ContinueOnError)
cl.flagSet.Usage = func() {
os.Stderr.WriteString(usage)
cl.flagSet.PrintDefaults()
}
cl.flagSet.StringVar(&cl.opt.KibanaIndex, "k", ".kibana", "Kibana index")
cl.flagSet.StringVar(&cl.opt.ES, "es", "http://127.0.0.1:9200", "Elasticsearch URL")
cl.flagSet.StringVar(&cl.opt.User, "user", "", "Username to connect to Elasticsearch. By default no username is passed.")
cl.flagSet.StringVar(&cl.opt.Pass, "pass", "", "Password to connect to Elasticsearch. By default no password is passed.")
cl.flagSet.StringVar(&cl.opt.Index, "i", "", "The Elasticsearch index name. This overwrites the index name defined in the dashboards and index pattern. Example: metricbeat-*")
cl.flagSet.StringVar(&cl.opt.Dir, "dir", "", "Directory containing the subdirectories: dashboard, visualization, search, index-pattern. Example: etc/kibana/")
cl.flagSet.StringVar(&cl.opt.File, "file", "", "Zip archive file containing the Beats dashboards. The archive contains a directory for each Beat.")
cl.flagSet.StringVar(&cl.opt.URL, "url",
fmt.Sprintf("https://artifacts.elastic.co/downloads/beats/beats-dashboards/beats-dashboards-%s.zip", lbeat.GetDefaultVersion()),
"URL to the zip archive containing the Beats dashboards")
cl.flagSet.StringVar(&cl.opt.Beat, "beat", beat, "The Beat name that is used to select what dashboards to install from a zip. An empty string selects all.")
cl.flagSet.BoolVar(&cl.opt.OnlyDashboards, "only-dashboards", false, "Import only dashboards together with visualizations and searches. By default import both, dashboards and the index-pattern.")
cl.flagSet.BoolVar(&cl.opt.OnlyIndex, "only-index", false, "Import only the index-pattern. By default imports both, dashboards and the index pattern.")
cl.flagSet.BoolVar(&cl.opt.Snapshot, "snapshot", false, "Import dashboards from snapshot builds.")
cl.flagSet.StringVar(&cl.opt.CertificateAuthority, "cacert", "", "Certificate Authority for server verification")
cl.flagSet.StringVar(&cl.opt.Certificate, "cert", "", "Certificate for SSL client authentication in PEM format.")
cl.flagSet.StringVar(&cl.opt.CertificateKey, "key", "", "Client Certificate Key in PEM format.")
cl.flagSet.BoolVar(&cl.opt.Insecure, "insecure", false, `Allows "insecure" SSL connections`)
cl.flagSet.BoolVar(&cl.opt.Quiet, "quiet", false, "Suppresses all status messages. Error messages are still printed to stderr.")
return &cl, nil
}
func (cl *CommandLine) ParseCommandLine() error {
cl.opt.Beat = beat
if err := cl.flagSet.Parse(os.Args[1:]); err != nil {
return err
}
if cl.opt.URL == "" && cl.opt.File == "" && cl.opt.Dir == "" {
return errors.New("Missing input. Please specify one of the options -file, -url or -dir")
}
if cl.opt.Certificate != "" && cl.opt.CertificateKey == "" {
return errors.New("A certificate key needs to be passed as well by using the -key option.")
}
if cl.opt.CertificateKey != "" && cl.opt.Certificate == "" {
return errors.New("A certificate needs to be passed as well by using the -cert option.")
}
return nil
}
func New() (*dashboards.Importer, error) {
/* define the command line arguments */
cl, err := DefineCommandLine()
if err != nil {
cl.flagSet.Usage()
return nil, err
}
/* parse command line arguments */
err = cl.ParseCommandLine()
if err != nil {
return nil, err
}
cfg := dashboards.DashboardsConfig{
Enabled: true,
KibanaIndex: cl.opt.KibanaIndex,
Index: cl.opt.Index,
Dir: cl.opt.Dir,
File: cl.opt.File,
Beat: cl.opt.Beat,
URL: cl.opt.URL,
OnlyDashboards: cl.opt.OnlyDashboards,
OnlyIndex: cl.opt.OnlyIndex,
Snapshot: cl.opt.Snapshot,
SnapshotURL: fmt.Sprintf("https://beats-nightlies.s3.amazonaws.com/dashboards/beats-dashboards-%s-SNAPSHOT.zip", lbeat.GetDefaultVersion()),
}
/* prepare the Elasticsearch index pattern */
fmtstr, err := fmtstr.CompileEvent(cl.opt.Index)
if err != nil {
return nil, fmt.Errorf("Failed to build the Elasticsearch index pattern: %s", err)
}
indexSel := outil.MakeSelector(outil.FmtSelectorExpr(fmtstr, ""))
var tlsConfig outputs.TLSConfig
var tls *transport.TLSConfig
if cl.opt.Insecure {
tlsConfig.VerificationMode = transport.VerifyNone
}
if len(cl.opt.Certificate) > 0 && len(cl.opt.CertificateKey) > 0 {
tlsConfig.Certificate = outputs.CertificateConfig{
Certificate: cl.opt.Certificate,
Key: cl.opt.CertificateKey,
}
}
if len(cl.opt.CertificateAuthority) > 0 {
tlsConfig.CAs = []string{cl.opt.CertificateAuthority}
}
tls, err = outputs.LoadTLSConfig(&tlsConfig)
if err != nil {
return nil, fmt.Errorf("Failed to load the SSL certificate: %s", err)
}
/* connect to Elasticsearch */
client, err := elasticsearch.NewClient(
elasticsearch.ClientSettings{
URL: cl.opt.ES,
Index: indexSel,
TLS: tls,
Username: cl.opt.User,
Password: cl.opt.Pass,
Timeout: 60 * time.Second,
},
nil,
)
if err != nil {
return nil, fmt.Errorf("Failed to connect to Elasticsearch: %s", err)
}
statusMsg := dashboards.MessageOutputter(func(msg string, a ...interface{}) {
if cl.opt.Quiet {
return
}
if len(a) == 0 {
fmt.Println(msg)
} else {
fmt.Println(fmt.Sprintf(msg, a...))
}
})
return dashboards.NewImporter(&cfg, client, &statusMsg)
}
func main() {
importer, err := New()
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Exiting")
os.Exit(1)
}
err = importer.Import()
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, "Exiting")
os.Exit(1)
}
}