github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/cmd/mattermost/commands/server.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package commands
     5  
     6  import (
     7  	"bytes"
     8  	"net"
     9  	"os"
    10  	"os/signal"
    11  	"runtime/debug"
    12  	"runtime/pprof"
    13  	"syscall"
    14  
    15  	"github.com/pkg/errors"
    16  	"github.com/spf13/cobra"
    17  
    18  	"github.com/mattermost/mattermost-server/v5/api4"
    19  	"github.com/mattermost/mattermost-server/v5/app"
    20  	"github.com/mattermost/mattermost-server/v5/config"
    21  	"github.com/mattermost/mattermost-server/v5/manualtesting"
    22  	"github.com/mattermost/mattermost-server/v5/mlog"
    23  	"github.com/mattermost/mattermost-server/v5/utils"
    24  	"github.com/mattermost/mattermost-server/v5/web"
    25  	"github.com/mattermost/mattermost-server/v5/wsapi"
    26  )
    27  
    28  var serverCmd = &cobra.Command{
    29  	Use:          "server",
    30  	Short:        "Run the Mattermost server",
    31  	RunE:         serverCmdF,
    32  	SilenceUsage: true,
    33  }
    34  
    35  func init() {
    36  	RootCmd.AddCommand(serverCmd)
    37  	RootCmd.RunE = serverCmdF
    38  }
    39  
    40  func serverCmdF(command *cobra.Command, args []string) error {
    41  	disableConfigWatch, _ := command.Flags().GetBool("disableconfigwatch")
    42  	usedPlatform, _ := command.Flags().GetBool("platform")
    43  
    44  	interruptChan := make(chan os.Signal, 1)
    45  
    46  	if err := utils.TranslationsPreInit(); err != nil {
    47  		return errors.Wrap(err, "unable to load Mattermost translation files")
    48  	}
    49  
    50  	customDefaults, err := loadCustomDefaults()
    51  	if err != nil {
    52  		mlog.Warn("Error loading custom configuration defaults: " + err.Error())
    53  	}
    54  
    55  	configStore, err := config.NewStore(getConfigDSN(command, config.GetEnvironment()), !disableConfigWatch, false, customDefaults)
    56  	if err != nil {
    57  		return errors.Wrap(err, "failed to load configuration")
    58  	}
    59  	defer configStore.Close()
    60  
    61  	return runServer(configStore, usedPlatform, interruptChan)
    62  }
    63  
    64  func runServer(configStore *config.Store, usedPlatform bool, interruptChan chan os.Signal) error {
    65  	// Setting the highest traceback level from the code.
    66  	// This is done to print goroutines from all threads (see golang.org/issue/13161)
    67  	// and also preserve a crash dump for later investigation.
    68  	debug.SetTraceback("crash")
    69  
    70  	options := []app.Option{
    71  		app.ConfigStore(configStore),
    72  		app.RunJobs,
    73  		app.JoinCluster,
    74  		app.StartSearchEngine,
    75  		app.StartMetrics,
    76  	}
    77  	server, err := app.NewServer(options...)
    78  	if err != nil {
    79  		mlog.Critical(err.Error())
    80  		return err
    81  	}
    82  	defer server.Shutdown()
    83  	// We add this after shutdown so that it can be called
    84  	// before server shutdown happens as it can close
    85  	// the advanced logger and prevent the mlog call from working properly.
    86  	defer func() {
    87  		// A panic pass-through layer which just logs it
    88  		// and sends it upwards.
    89  		if x := recover(); x != nil {
    90  			var buf bytes.Buffer
    91  			pprof.Lookup("goroutine").WriteTo(&buf, 2)
    92  			mlog.Critical("A panic occurred",
    93  				mlog.Any("error", x),
    94  				mlog.String("stack", buf.String()))
    95  			panic(x)
    96  		}
    97  	}()
    98  
    99  	if usedPlatform {
   100  		mlog.Warn("The platform binary has been deprecated, please switch to using the mattermost binary.")
   101  	}
   102  
   103  	api := api4.Init(server, server.AppOptions, server.Router)
   104  	wsapi.Init(server)
   105  	web.New(server, server.AppOptions, server.Router)
   106  	api4.InitLocal(server, server.AppOptions, server.LocalRouter)
   107  
   108  	serverErr := server.Start()
   109  	if serverErr != nil {
   110  		mlog.Critical(serverErr.Error())
   111  		return serverErr
   112  	}
   113  
   114  	// If we allow testing then listen for manual testing URL hits
   115  	if *server.Config().ServiceSettings.EnableTesting {
   116  		manualtesting.Init(api)
   117  	}
   118  
   119  	notifyReady()
   120  
   121  	// wait for kill signal before attempting to gracefully shutdown
   122  	// the running service
   123  	signal.Notify(interruptChan, syscall.SIGINT, syscall.SIGTERM)
   124  	<-interruptChan
   125  
   126  	return nil
   127  }
   128  
   129  func notifyReady() {
   130  	// If the environment vars provide a systemd notification socket,
   131  	// notify systemd that the server is ready.
   132  	systemdSocket := os.Getenv("NOTIFY_SOCKET")
   133  	if systemdSocket != "" {
   134  		mlog.Info("Sending systemd READY notification.")
   135  
   136  		err := sendSystemdReadyNotification(systemdSocket)
   137  		if err != nil {
   138  			mlog.Error(err.Error())
   139  		}
   140  	}
   141  }
   142  
   143  func sendSystemdReadyNotification(socketPath string) error {
   144  	msg := "READY=1"
   145  	addr := &net.UnixAddr{
   146  		Name: socketPath,
   147  		Net:  "unixgram",
   148  	}
   149  	conn, err := net.DialUnix(addr.Net, nil, addr)
   150  	if err != nil {
   151  		return err
   152  	}
   153  	defer conn.Close()
   154  	_, err = conn.Write([]byte(msg))
   155  	return err
   156  }