From c209e4457457edc042f063390c9a222a694f3a6d Mon Sep 17 00:00:00 2001 From: Derrick Anderson Date: Mon, 12 Feb 2018 16:01:02 -0500 Subject: revert master changes --- cmd/platform/channel.go | 17 +++-------- cmd/platform/channel_test.go | 27 ----------------- cmd/platform/jobserver.go | 2 +- cmd/platform/server.go | 19 +++++------- cmd/platform/server_test.go | 72 -------------------------------------------- cmd/platform/test.go | 12 ++------ 6 files changed, 14 insertions(+), 135 deletions(-) delete mode 100644 cmd/platform/server_test.go (limited to 'cmd') diff --git a/cmd/platform/channel.go b/cmd/platform/channel.go index 5d86ad9da..98bdcebb8 100644 --- a/cmd/platform/channel.go +++ b/cmd/platform/channel.go @@ -106,8 +106,6 @@ func init() { channelCreateCmd.Flags().String("purpose", "", "Channel purpose") channelCreateCmd.Flags().Bool("private", false, "Create a private channel.") - moveChannelsCmd.Flags().String("username", "", "Required. Username who is moving the channel.") - deleteChannelsCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the channels.") modifyChannelCmd.Flags().Bool("private", false, "Convert the channel to a private channel") @@ -321,33 +319,26 @@ func moveChannelsCmdF(cmd *cobra.Command, args []string) error { return errors.New("Unable to find destination team '" + args[0] + "'") } - username, erru := cmd.Flags().GetString("username") - if erru != nil || username == "" { - return errors.New("Username is required") - } - user := getUserFromUserArg(a, username) - channels := getChannelsFromChannelArgs(a, args[1:]) for i, channel := range channels { if channel == nil { CommandPrintErrorln("Unable to find channel '" + args[i] + "'") continue } - originTeamID := channel.TeamId - if err := moveChannel(a, team, channel, user); err != nil { + if err := moveChannel(a, team, channel); err != nil { CommandPrintErrorln("Unable to move channel '" + channel.Name + "' error: " + err.Error()) } else { - CommandPrettyPrintln("Moved channel '" + channel.Name + "' to " + team.Name + "(" + team.Id + ") from " + originTeamID + ".") + CommandPrettyPrintln("Moved channel '" + channel.Name + "'") } } return nil } -func moveChannel(a *app.App, team *model.Team, channel *model.Channel, user *model.User) *model.AppError { +func moveChannel(a *app.App, team *model.Team, channel *model.Channel) *model.AppError { oldTeamId := channel.TeamId - if err := a.MoveChannel(team, channel, user); err != nil { + if err := a.MoveChannel(team, channel); err != nil { return err } diff --git a/cmd/platform/channel_test.go b/cmd/platform/channel_test.go index cf8603cf3..1e6915679 100644 --- a/cmd/platform/channel_test.go +++ b/cmd/platform/channel_test.go @@ -44,33 +44,6 @@ func TestRemoveChannel(t *testing.T) { checkCommand(t, "channel", "remove", th.BasicTeam.Name+":"+channel.Name, th.BasicUser2.Email) } -func TestMoveChannel(t *testing.T) { - th := api.Setup().InitBasic() - defer th.TearDown() - - client := th.BasicClient - team1 := th.BasicTeam - team2 := th.CreateTeam(client) - user1 := th.BasicUser - th.LinkUserToTeam(user1, team2) - channel := th.BasicChannel - - th.LinkUserToTeam(user1, team1) - th.LinkUserToTeam(user1, team2) - - adminEmail := user1.Email - adminUsername := user1.Username - origin := team1.Name + ":" + channel.Name - dest := team2.Name - - checkCommand(t, "channel", "add", origin, adminEmail) - - // should fail with nill because errors are logged instead of returned when a channel does not exist - require.Nil(t, runCommand(t, "channel", "move", dest, team1.Name+":doesnotexist", "--username", adminUsername)) - - checkCommand(t, "channel", "move", dest, origin, "--username", adminUsername) -} - func TestListChannels(t *testing.T) { th := api.Setup().InitBasic() defer th.TearDown() diff --git a/cmd/platform/jobserver.go b/cmd/platform/jobserver.go index 044ee6b6a..e664136c0 100644 --- a/cmd/platform/jobserver.go +++ b/cmd/platform/jobserver.go @@ -35,7 +35,7 @@ func jobserverCmdF(cmd *cobra.Command, args []string) { defer l4g.Close() defer a.Shutdown() - a.LoadLicense() + a.Jobs.LoadLicense() // Run jobs l4g.Info("Starting Mattermost job server") diff --git a/cmd/platform/server.go b/cmd/platform/server.go index 1b411cf20..e3742cef6 100644 --- a/cmd/platform/server.go +++ b/cmd/platform/server.go @@ -42,11 +42,10 @@ func runServerCmd(cmd *cobra.Command, args []string) error { disableConfigWatch, _ := cmd.Flags().GetBool("disableconfigwatch") - interruptChan := make(chan os.Signal, 1) - return runServer(config, disableConfigWatch, interruptChan) + return runServer(config, disableConfigWatch) } -func runServer(configFileLocation string, disableConfigWatch bool, interruptChan chan os.Signal) error { +func runServer(configFileLocation string, disableConfigWatch bool) error { options := []app.Option{app.ConfigFile(configFileLocation)} if disableConfigWatch { options = append(options, app.DisableConfigWatch) @@ -54,7 +53,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan a, err := app.New(options...) if err != nil { - l4g.Critical(err.Error()) + l4g.Error(err.Error()) return err } defer a.Shutdown() @@ -88,12 +87,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan } }) - serverErr := a.StartServer() - if serverErr != nil { - l4g.Critical(serverErr.Error()) - return serverErr - } - + a.StartServer() api4.Init(a, a.Srv.Router, false) api3 := api.Init(a, a.Srv.Router) wsapi.Init(a, a.Srv.WebSocketRouter) @@ -166,8 +160,9 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan // wait for kill signal before attempting to gracefully shutdown // the running service - signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - <-interruptChan + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + <-c if a.Cluster != nil { a.Cluster.StopInterNodeCommunication() diff --git a/cmd/platform/server_test.go b/cmd/platform/server_test.go deleted file mode 100644 index 15f9a357a..000000000 --- a/cmd/platform/server_test.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package main - -import ( - "io/ioutil" - "os" - "syscall" - "testing" - - "github.com/mattermost/mattermost-server/jobs" - "github.com/mattermost/mattermost-server/utils" - "github.com/stretchr/testify/require" -) - -type ServerTestHelper struct { - configPath string - disableConfigWatch bool - interruptChan chan os.Signal - originalInterval int -} - -func SetupServerTest() *ServerTestHelper { - // Build a channel that will be used by the server to receive system signals… - interruptChan := make(chan os.Signal, 1) - // …and sent it immediately a SIGINT value. - // This will make the server loop stop as soon as it started successfully. - interruptChan <- syscall.SIGINT - - // Let jobs poll for termination every 0.2s (instead of every 15s by default) - // Otherwise we would have to wait the whole polling duration before the test - // terminates. - originalInterval := jobs.DEFAULT_WATCHER_POLLING_INTERVAL - jobs.DEFAULT_WATCHER_POLLING_INTERVAL = 200 - - th := &ServerTestHelper{ - configPath: utils.FindConfigFile("config.json"), - disableConfigWatch: true, - interruptChan: interruptChan, - originalInterval: originalInterval, - } - return th -} - -func (th *ServerTestHelper) TearDownServerTest() { - jobs.DEFAULT_WATCHER_POLLING_INTERVAL = th.originalInterval -} - -func TestRunServerSuccess(t *testing.T) { - th := SetupServerTest() - defer th.TearDownServerTest() - - err := runServer(th.configPath, th.disableConfigWatch, th.interruptChan) - require.NoError(t, err) -} - -func TestRunServerInvalidConfigFile(t *testing.T) { - th := SetupServerTest() - defer th.TearDownServerTest() - - // Start the server with an unreadable config file - unreadableConfigFile, err := ioutil.TempFile("", "mattermost-unreadable-config-file-") - if err != nil { - panic(err) - } - os.Chmod(unreadableConfigFile.Name(), 0200) - defer os.Remove(unreadableConfigFile.Name()) - - err = runServer(unreadableConfigFile.Name(), th.disableConfigWatch, th.interruptChan) - require.Error(t, err) -} diff --git a/cmd/platform/test.go b/cmd/platform/test.go index 9ab3fbb36..036df07de 100644 --- a/cmd/platform/test.go +++ b/cmd/platform/test.go @@ -53,11 +53,7 @@ func webClientTestsCmdF(cmd *cobra.Command, args []string) error { defer a.Shutdown() utils.InitTranslations(a.Config().LocalizationSettings) - serverErr := a.StartServer() - if serverErr != nil { - return serverErr - } - + a.StartServer() api4.Init(a, a.Srv.Router, false) api.Init(a, a.Srv.Router) wsapi.Init(a, a.Srv.WebSocketRouter) @@ -75,11 +71,7 @@ func serverForWebClientTestsCmdF(cmd *cobra.Command, args []string) error { defer a.Shutdown() utils.InitTranslations(a.Config().LocalizationSettings) - serverErr := a.StartServer() - if serverErr != nil { - return serverErr - } - + a.StartServer() api4.Init(a, a.Srv.Router, false) api.Init(a, a.Srv.Router) wsapi.Init(a, a.Srv.WebSocketRouter) -- cgit v1.2.3-1-g7c22 From e43f381764bdf29117760b26c88fd37b716e67b2 Mon Sep 17 00:00:00 2001 From: Derrick Anderson Date: Tue, 13 Feb 2018 23:46:49 -0500 Subject: gofmt --- cmd/platform/server.go | 2 +- cmd/platform/server_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/platform/server.go b/cmd/platform/server.go index 0421fcc05..1b411cf20 100644 --- a/cmd/platform/server.go +++ b/cmd/platform/server.go @@ -93,7 +93,7 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan l4g.Critical(serverErr.Error()) return serverErr } - + api4.Init(a, a.Srv.Router, false) api3 := api.Init(a, a.Srv.Router) wsapi.Init(a, a.Srv.WebSocketRouter) diff --git a/cmd/platform/server_test.go b/cmd/platform/server_test.go index 2b68fc703..15f9a357a 100644 --- a/cmd/platform/server_test.go +++ b/cmd/platform/server_test.go @@ -69,4 +69,4 @@ func TestRunServerInvalidConfigFile(t *testing.T) { err = runServer(unreadableConfigFile.Name(), th.disableConfigWatch, th.interruptChan) require.Error(t, err) -} \ No newline at end of file +} -- cgit v1.2.3-1-g7c22 From 44a27125de1b4658f1149f5bc459468a056b4d7d Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 14 Feb 2018 23:48:06 +0530 Subject: Wait for goroutines to finish before shuting down server (#8259) When running server tests, the server will exit while some jobs spawned through a goroutine are still running. This may crash the test harness, as the jobs try to access a shut down app instance. Fortunately the fix is easy: we just have to use the same App goroutine-counting facility than the rest of the method's goroutines. --- cmd/platform/server.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'cmd') diff --git a/cmd/platform/server.go b/cmd/platform/server.go index 1b411cf20..80b38401e 100644 --- a/cmd/platform/server.go +++ b/cmd/platform/server.go @@ -130,11 +130,21 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan a.EnsureDiagnosticId() - go runSecurityJob(a) - go runDiagnosticsJob(a) - go runSessionCleanupJob(a) - go runTokenCleanupJob(a) - go runCommandWebhookCleanupJob(a) + a.Go(func() { + runSecurityJob(a) + }) + a.Go(func() { + runDiagnosticsJob(a) + }) + a.Go(func() { + runSessionCleanupJob(a) + }) + a.Go(func() { + runTokenCleanupJob(a) + }) + a.Go(func() { + runCommandWebhookCleanupJob(a) + }) if complianceI := a.Compliance; complianceI != nil { complianceI.StartComplianceDailyJob() -- cgit v1.2.3-1-g7c22 From b112747de76f9c11c4d8083207049fac6e435019 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Fri, 16 Feb 2018 06:17:03 +0530 Subject: Send systemd READY notification (#8296) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when starting Mattermost programmatically, it's hard to tell when the server is actually ready to receive network connections. This isn't convenient for monitoring (the systemd service status is "running" although the server is still booting), nor for programatic use (where a script would need to know when the server is ready to perform further actions). To improve this, systemd allow processes to tell when they started successfully. The launcher waits for this notification before reporting the service as successfully launched. The way processes notify systemd is by sending a `READY=1` string over a standard unix socket, whose path is provided in an environment var. The systemd service is then told to expect this notification: ```diff [Service] -Type=simple +Type=notify ExecStart=/home/vagrant/go/bin/platform ``` Now, when starting the server, systemd will actually wait for the server to be ready before returning the control to the shell. Additionally, during this time, querying the server status with `service mattermost status` will report the service as "activating" – before transitioning to "running" when the server is ready. --- cmd/platform/server.go | 32 +++++++++++++++++++++++ cmd/platform/server_test.go | 64 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) (limited to 'cmd') diff --git a/cmd/platform/server.go b/cmd/platform/server.go index 80b38401e..31606e6eb 100644 --- a/cmd/platform/server.go +++ b/cmd/platform/server.go @@ -4,6 +4,7 @@ package main import ( + "net" "os" "os/signal" "syscall" @@ -174,6 +175,8 @@ func runServer(configFileLocation string, disableConfigWatch bool, interruptChan a.Jobs.StartSchedulers() } + notifyReady() + // wait for kill signal before attempting to gracefully shutdown // the running service signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) @@ -244,6 +247,35 @@ func doDiagnostics(a *app.App) { } } +func notifyReady() { + // If the environment vars provide a systemd notification socket, + // notify systemd that the server is ready. + systemdSocket := os.Getenv("NOTIFY_SOCKET") + if systemdSocket != "" { + l4g.Info("Sending systemd READY notification.") + + err := sendSystemdReadyNotification(systemdSocket) + if err != nil { + l4g.Error(err.Error()) + } + } +} + +func sendSystemdReadyNotification(socketPath string) error { + msg := "READY=1" + addr := &net.UnixAddr{ + Name: socketPath, + Net: "unixgram", + } + conn, err := net.DialUnix(addr.Net, nil, addr) + if err != nil { + return err + } + defer conn.Close() + _, err = conn.Write([]byte(msg)) + return err +} + func doTokenCleanup(a *app.App) { a.Srv.Store.Token().Cleanup() } diff --git a/cmd/platform/server_test.go b/cmd/platform/server_test.go index 15f9a357a..2f04e7d15 100644 --- a/cmd/platform/server_test.go +++ b/cmd/platform/server_test.go @@ -5,6 +5,7 @@ package main import ( "io/ioutil" + "net" "os" "syscall" "testing" @@ -70,3 +71,66 @@ func TestRunServerInvalidConfigFile(t *testing.T) { err = runServer(unreadableConfigFile.Name(), th.disableConfigWatch, th.interruptChan) require.Error(t, err) } + +func TestRunServerSystemdNotification(t *testing.T) { + th := SetupServerTest() + defer th.TearDownServerTest() + + // Get a random temporary filename for using as a mock systemd socket + socketFile, err := ioutil.TempFile("", "mattermost-systemd-mock-socket-") + if err != nil { + panic(err) + } + socketPath := socketFile.Name() + os.Remove(socketPath) + + // Set the socket path in the process environment + originalSocket := os.Getenv("NOTIFY_SOCKET") + os.Setenv("NOTIFY_SOCKET", socketPath) + defer os.Setenv("NOTIFY_SOCKET", originalSocket) + + // Open the socket connection + addr := &net.UnixAddr{ + Name: socketPath, + Net: "unixgram", + } + connection, err := net.ListenUnixgram("unixgram", addr) + if err != nil { + panic(err) + } + defer connection.Close() + defer os.Remove(socketPath) + + // Listen for socket data + socketReader := make(chan string) + go func(ch chan string) { + buffer := make([]byte, 512) + count, err := connection.Read(buffer) + if err != nil { + panic(err) + } + data := buffer[0:count] + ch<- string(data) + }(socketReader) + + // Start and stop the server + err = runServer(th.configPath, th.disableConfigWatch, th.interruptChan) + require.NoError(t, err) + + // Ensure the notification has been sent on the socket and is correct + notification := <-socketReader + require.Equal(t, notification, "READY=1") +} + +func TestRunServerNoSystemd(t *testing.T) { + th := SetupServerTest() + defer th.TearDownServerTest() + + // Temporarily remove any Systemd socket defined in the environment + originalSocket := os.Getenv("NOTIFY_SOCKET") + os.Unsetenv("NOTIFY_SOCKET") + defer os.Setenv("NOTIFY_SOCKET", originalSocket) + + err := runServer(th.configPath, th.disableConfigWatch, th.interruptChan) + require.NoError(t, err) +} -- cgit v1.2.3-1-g7c22 From 6d8f122a5160f6d9e4c51579f2429dfaa62c7271 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Fri, 16 Feb 2018 06:47:51 -0800 Subject: Upgrading server dependancies (#8308) --- cmd/platform/mattermost.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'cmd') diff --git a/cmd/platform/mattermost.go b/cmd/platform/mattermost.go index b0190011b..e4a120e1e 100644 --- a/cmd/platform/mattermost.go +++ b/cmd/platform/mattermost.go @@ -25,6 +25,9 @@ import ( _ "github.com/prometheus/client_golang/prometheus/promhttp" _ "github.com/tylerb/graceful" _ "gopkg.in/olivere/elastic.v5" + + // Temp imports for new dependencies + _ "github.com/gorilla/schema" ) func main() { -- cgit v1.2.3-1-g7c22