Permalink
Jan 14, 2016
Newer
100644
320 lines (285 sloc)
9.41 KB
1
// Copyright 2015 The Cockroach Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
// implied. See the License for the specific language governing
14
//
15
// Author: Andrew Bonventre (andybons@gmail.com)
16
// Author: Spencer Kimball (spencer.kimball@gmail.com)
17
18
package cli
19
20
import (
35
"github.com/cockroachdb/cockroach/server"
36
"github.com/cockroachdb/cockroach/storage/engine"
44
var errMissingParams = errors.New("missing or invalid parameters")
45
46
// panicGuard wraps an errorless command into one wrapping panics into errors.
47
// This simplifies error handling for many commands for which more elaborate
48
// error handling isn't needed and would otherwise bloat the code.
51
func panicGuard(cmdFn func(*cobra.Command, []string)) func(*cobra.Command, []string) error {
52
return func(c *cobra.Command, args []string) (err error) {
53
defer func() {
54
if r := recover(); r != nil {
55
err = fmt.Errorf("%v", r)
56
}
57
}()
58
cmdFn(c, args)
59
return nil
60
}
61
}
62
63
// panicf is only to be used when wrapped through panicGuard, since the
64
// stack trace doesn't matter then.
65
func panicf(format string, args ...interface{}) {
66
panic(fmt.Sprintf(format, args...))
67
}
68
69
// getJSON is a convenience wrapper around util.GetJSON that uses our Context to populate
70
// parts of the request.
71
func getJSON(hostport, path string, v interface{}) error {
87
88
If no cluster exists yet and this is the first node, no additional
89
flags are required. If the cluster already exists, and this node is
90
uninitialized, specify the --join flag to point to any healthy node
91
(or list of nodes) already part of the cluster.
92
`,
93
Example: ` cockroach start --insecure --store=attrs=ssd,path=/mnt/ssd1 [--join=host:port,[host:port]]`,
98
func setDefaultCacheSize(ctx *server.Context) {
99
if size, err := server.GetTotalMemory(); err == nil {
100
// Default the cache size to 1/4 of total memory. A larger cache size
101
// doesn't necessarily improve performance as this is memory that is
102
// dedicated to uncompressed blocks in RocksDB. A larger value here will
103
// compete with the OS buffer cache which holds compressed blocks.
104
ctx.CacheSize = size / 4
108
func initInsecure() error {
109
if !cliContext.Insecure || insecure.isSet {
110
return nil
111
}
112
// The --insecure flag was not specified on the command line, verify that the
113
// host refers to a loopback address.
114
if connHost != "" {
115
addr, err := net.ResolveIPAddr("ip", connHost)
116
if err != nil {
117
return err
118
}
119
if !addr.IP.IsLoopback() {
120
return fmt.Errorf("specify --insecure to listen on external address %s", connHost)
121
}
123
cliContext.Addr = net.JoinHostPort("localhost", connPort)
124
cliContext.HTTPAddr = net.JoinHostPort("localhost", httpPort)
125
}
126
return nil
127
}
128
129
// runStart starts the cockroach node using --store as the list of
130
// storage devices ("stores") on this machine and --join as the list
131
// of other active nodes used to join this node to the cockroach
132
// cluster, if this is its first time connecting.
133
func runStart(_ *cobra.Command, _ []string) error {
138
// Default the log directory to the the "logs" subdirectory of the first
139
// non-memory store. We only do this for the "start" command which is why
140
// this work occurs here and not in an OnInitialize function.
154
// Make sure the path exists
155
if err := os.MkdirAll(f.Value.String(), 0755); err != nil {
156
return err
157
}
158
173
if err != nil {
174
return fmt.Errorf("failed to start Cockroach server: %s", err)
175
}
176
177
// We don't do this in NewServer since we don't want it in tests.
178
if err := s.SetupReportingURLs(); err != nil {
179
return err
180
}
181
182
if err := s.Start(); err != nil {
183
return fmt.Errorf("cockroach server exited with error: %s", err)
186
pgURL, err := cliContext.PGURL(connUser)
187
if err != nil {
188
return err
189
}
190
196
if len(cliContext.SocketFile) != 0 {
197
fmt.Fprintf(tw, "socket:\t%s\n", cliContext.SocketFile)
198
}
207
signalCh := make(chan os.Signal, 1)
208
signal.Notify(signalCh, os.Interrupt, os.Kill)
209
// TODO(spencer): move this behind a build tag.
210
signal.Notify(signalCh, syscall.SIGTERM)
212
// Block until one of the signals above is received or the stopper
213
// is stopped externally (for example, via the quit endpoint).
220
const msgDrain = "initiating graceful shutdown of server"
221
log.Info(msgDrain)
222
fmt.Fprintln(os.Stdout, msgDrain)
224
go func() {
225
ticker := time.NewTicker(5 * time.Second)
226
defer ticker.Stop()
227
for {
228
select {
229
case <-ticker.C:
230
if log.V(1) {
231
log.Infof("running tasks:\n%s", stopper.RunningTasks())
232
}
233
log.Infof("%d running tasks", stopper.NumTasks())
234
case <-stopper.ShouldStop():
235
return
236
}
237
}
238
}()
239
246
const msgDone = "server drained and shutdown completed"
247
log.Infof(msgDone)
248
fmt.Fprintln(os.Stdout, msgDone)
254
// exterminateCmd command shuts down the node server and
255
// destroys all data held by the node.
256
var exterminateCmd = &cobra.Command{
257
Use: "exterminate",
258
Short: "destroy all data held by the node",
275
if err := runQuit(nil, nil); err != nil {
276
return util.Errorf("shutdown node error: %s", err)
277
}
281
if rocksdb, ok := e.(*engine.RocksDB); ok {
282
log.Infof("exterminating data from store %s", e)
283
if err := rocksdb.Destroy(); err != nil {
293
var quitCmd = &cobra.Command{
294
Use: "quit",
295
Short: "drain and shutdown node\n",
296
Long: `
297
Shutdown the server. The first stage is drain, where any new requests
298
will be ignored by the server. When all extant requests have been
299
completed, the server exits.
300
`,
307
admin, err := client.NewAdminClient(&cliContext.Context.Context, cliContext.HTTPAddr, client.Quit)
312
// TODO(tschottdorf): needs cleanup. An error here can happen if the shutdown
313
// happened faster than the HTTP request made it back.