1
// Copyright 2018 The CubeFS Authors.
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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
13
// permissions and limitations under the License.
32
"github.com/cubefs/cubefs/authnode"
33
"github.com/cubefs/cubefs/cmd/common"
34
"github.com/cubefs/cubefs/console"
35
"github.com/cubefs/cubefs/datanode"
36
"github.com/cubefs/cubefs/lcnode"
37
"github.com/cubefs/cubefs/master"
38
"github.com/cubefs/cubefs/metanode"
39
"github.com/cubefs/cubefs/objectnode"
40
"github.com/cubefs/cubefs/proto"
41
"github.com/cubefs/cubefs/util/auditlog"
42
"github.com/cubefs/cubefs/util/config"
43
"github.com/cubefs/cubefs/util/errors"
44
"github.com/cubefs/cubefs/util/log"
45
sysutil "github.com/cubefs/cubefs/util/sys"
46
"github.com/cubefs/cubefs/util/ump"
47
"github.com/jacobsa/daemonize"
51
ConfigKeyRole = "role"
52
ConfigKeyLogDir = "logDir"
53
ConfigKeyLogLevel = "logLevel"
54
ConfigKeyLogRotateSize = "logRotateSize"
55
ConfigKeyLogRotateHeadRoom = "logRotateHeadRoom"
56
ConfigKeyProfPort = "prof"
57
ConfigKeyWarnLogDir = "warnLogDir"
58
ConfigKeyBuffersTotalLimit = "buffersTotalLimit"
59
ConfigKeyLogLeftSpaceLimit = "logLeftSpaceLimit"
67
RoleObject = "objectnode"
68
RoleConsole = "console"
69
RoleLifeCycle = "lcnode"
73
ModuleMaster = "master"
74
ModuleMeta = "metaNode"
75
ModuleData = "dataNode"
76
ModuleAuth = "authNode"
77
ModuleObject = "objectNode"
78
ModuleConsole = "console"
79
ModuleLifeCycle = "lcnode"
83
LoggerOutput = "output.log"
87
configFile = flag.String("c", "", "config file path")
88
configVersion = flag.Bool("v", false, "show version")
89
configForeground = flag.Bool("f", false, "run foreground")
90
redirectSTD = flag.Bool("redirect-std", true, "redirect standard output to file")
93
func interceptSignal(s common.Server) {
94
sigC := make(chan os.Signal, 1)
95
signal.Notify(sigC, syscall.SIGINT, syscall.SIGTERM)
96
syslog.Println("action[interceptSignal] register system signal.")
100
syslog.Printf("action[interceptSignal] received signal: %s. pid %d", sig.String(), os.Getpid())
106
func modifyOpenFiles() (err error) {
107
var rLimit syscall.Rlimit
108
err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
110
return fmt.Errorf("Error Getting Rlimit %v", err.Error())
112
syslog.Println(rLimit)
115
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
117
return fmt.Errorf("Error Setting Rlimit %v", err.Error())
119
err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
121
return fmt.Errorf("Error Getting Rlimit %v", err.Error())
123
syslog.Println("Rlimit Final", rLimit)
130
Version := proto.DumpVersion("Server")
132
fmt.Printf("%v", Version)
137
* LoadConfigFile should be checked before start daemon, since it will
138
* call os.Exit() w/o notifying the parent process.
140
cfg, err := config.LoadConfigFile(*configFile)
142
daemonize.SignalOutcome(err)
146
if !*configForeground {
147
if err := startDaemon(); err != nil {
148
fmt.Printf("Server start failed: %v\n", err)
155
* We are in daemon from here.
156
* Must notify the parent process through SignalOutcome anyway.
159
role := cfg.GetString(ConfigKeyRole)
160
logDir := cfg.GetString(ConfigKeyLogDir)
161
logLevel := cfg.GetString(ConfigKeyLogLevel)
162
logRotateSize := cfg.GetInt64(ConfigKeyLogRotateSize)
163
logRotateHeadRoom := cfg.GetInt64(ConfigKeyLogRotateHeadRoom)
164
profPort := cfg.GetString(ConfigKeyProfPort)
165
umpDatadir := cfg.GetString(ConfigKeyWarnLogDir)
166
buffersTotalLimit := cfg.GetInt64(ConfigKeyBuffersTotalLimit)
167
logLeftSpaceLimitStr := cfg.GetString(ConfigKeyLogLeftSpaceLimit)
168
logLeftSpaceLimit, err := strconv.ParseInt(logLeftSpaceLimitStr, 10, 64)
169
if err != nil || logLeftSpaceLimit == 0 {
170
log.LogErrorf("logLeftSpaceLimit is not a legal int value: %v", err.Error())
171
logLeftSpaceLimit = log.DefaultLogLeftSpaceLimit
173
// Init server instance with specified role configuration.
180
server = metanode.NewServer()
183
server = master.NewServer()
184
module = ModuleMaster
186
server = datanode.NewServer()
189
server = authnode.NewServer()
192
server = objectnode.NewServer()
193
module = ModuleObject
195
server = console.NewServer()
196
module = ModuleConsole
198
server = lcnode.NewServer()
199
module = ModuleLifeCycle
201
err = errors.NewErrorf("Fatal: role mismatch: %s", role)
203
daemonize.SignalOutcome(err)
211
switch strings.ToLower(logLevel) {
213
level = log.DebugLevel
215
level = log.InfoLevel
217
level = log.WarnLevel
219
level = log.ErrorLevel
221
level = log.CriticalLevel
223
level = log.ErrorLevel
225
rotate := log.NewLogRotate()
226
if logRotateSize > 0 {
227
rotate.SetRotateSizeMb(logRotateSize)
229
if logRotateHeadRoom > 0 {
230
rotate.SetHeadRoomMb(logRotateHeadRoom)
232
_, err = log.InitLog(logDir, module, level, rotate, logLeftSpaceLimit)
234
err = errors.NewErrorf("Fatal: failed to init log - %v", err)
236
daemonize.SignalOutcome(err)
240
if errors.SupportPanicHook() {
241
err = errors.AtPanic(func() {
245
log.LogErrorf("failed to hook go panic")
250
_, err = auditlog.InitAudit(logDir, module, auditlog.DefaultAuditLogSize)
252
err = errors.NewErrorf("Fatal: failed to init audit log - %v", err)
254
daemonize.SignalOutcome(err)
257
defer auditlog.StopAudit()
261
outputFilePath := path.Join(logDir, module, LoggerOutput)
262
outputFile, err := os.OpenFile(outputFilePath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0o666)
264
err = errors.NewErrorf("Fatal: failed to open output path - %v", err)
266
daemonize.SignalOutcome(err)
274
syslog.SetOutput(outputFile)
275
if err = sysutil.RedirectFD(int(outputFile.Fd()), int(os.Stderr.Fd())); err != nil {
276
err = errors.NewErrorf("Fatal: failed to redirect fd - %v", err)
278
daemonize.SignalOutcome(err)
283
if buffersTotalLimit < 0 {
284
syslog.Printf("invalid fields, BuffersTotalLimit(%v) must larger or equal than 0\n", buffersTotalLimit)
288
proto.InitBufferPool(buffersTotalLimit)
289
syslog.Printf("Hello, CubeFS Storage\n%s\n", Version)
290
err = modifyOpenFiles()
292
err = errors.NewErrorf("Fatal: failed to modify open files - %v", err)
294
daemonize.SignalOutcome(err)
298
// for multi-cpu scheduling
299
runtime.GOMAXPROCS(runtime.NumCPU())
300
if err = ump.InitUmp(role, umpDatadir); err != nil {
302
err = errors.NewErrorf("Fatal: failed to init ump warnLogDir - %v", err)
304
daemonize.SignalOutcome(err)
310
mainMux := http.NewServeMux()
311
mux := http.NewServeMux()
312
http.HandleFunc(log.SetLogLevelPath, log.SetLogLevel)
313
mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
314
mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
315
mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
316
mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
317
mux.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace))
318
mux.Handle("/debug/", http.HandlerFunc(pprof.Index))
319
mainHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
320
if strings.HasPrefix(req.URL.Path, "/debug/") {
321
mux.ServeHTTP(w, req)
323
http.DefaultServeMux.ServeHTTP(w, req)
326
mainMux.Handle("/", mainHandler)
327
e := http.ListenAndServe(fmt.Sprintf(":%v", profPort), mainMux)
330
err = errors.NewErrorf("cannot listen pprof %v err %v", profPort, e)
332
daemonize.SignalOutcome(err)
338
interceptSignal(server)
339
err = server.Start(cfg)
342
err = errors.NewErrorf("Fatal: failed to start the CubeFS %s daemon err %v - ", role, err)
344
daemonize.SignalOutcome(err)
348
syslog.Printf("server start success, pid %d, role %s", os.Getpid(), role)
349
log.LogDisableStderrOutput()
350
err = log.OutputPid(logDir, role)
353
err = errors.NewErrorf("Fatal: failed to print pid %s err %v - ", role, err)
355
daemonize.SignalOutcome(err)
359
daemonize.SignalOutcome(nil)
361
// Block main goroutine until server shutdown.
367
func startDaemon() error {
368
cmdPath, err := os.Executable()
370
return fmt.Errorf("startDaemon failed: cannot get absolute command path, err(%v)", err)
373
configPath, err := filepath.Abs(*configFile)
375
return fmt.Errorf("startDaemon failed: cannot get absolute command path of config file(%v) , err(%v)", *configFile, err)
378
args := []string{"-f"}
379
args = append(args, "-c")
380
args = append(args, configPath)
383
fmt.Sprintf("PATH=%s", os.Getenv("PATH")),
386
err = daemonize.Run(cmdPath, args, env, os.Stdout)
388
return fmt.Errorf("startDaemon failed: daemon start failed, cmd(%v) args(%v) env(%v) err(%v)\n", cmdPath, args, env, err)