github.com/mad-app/mattermost-server@v5.11.1+incompatible/app/admin.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"io"
     8  	"os"
     9  	"time"
    10  
    11  	"runtime/debug"
    12  
    13  	"net/http"
    14  
    15  	"github.com/mattermost/mattermost-server/mlog"
    16  	"github.com/mattermost/mattermost-server/model"
    17  	"github.com/mattermost/mattermost-server/services/mailservice"
    18  	"github.com/mattermost/mattermost-server/utils"
    19  )
    20  
    21  func (a *App) GetLogs(page, perPage int) ([]string, *model.AppError) {
    22  	var lines []string
    23  	if a.Cluster != nil && *a.Config().ClusterSettings.Enable {
    24  		lines = append(lines, "-----------------------------------------------------------------------------------------------------------")
    25  		lines = append(lines, "-----------------------------------------------------------------------------------------------------------")
    26  		lines = append(lines, a.Cluster.GetMyClusterInfo().Hostname)
    27  		lines = append(lines, "-----------------------------------------------------------------------------------------------------------")
    28  		lines = append(lines, "-----------------------------------------------------------------------------------------------------------")
    29  	}
    30  
    31  	melines, err := a.GetLogsSkipSend(page, perPage)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	lines = append(lines, melines...)
    37  
    38  	if a.Cluster != nil && *a.Config().ClusterSettings.Enable {
    39  		clines, err := a.Cluster.GetLogs(page, perPage)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  
    44  		lines = append(lines, clines...)
    45  	}
    46  
    47  	return lines, nil
    48  }
    49  
    50  func (a *App) GetLogsSkipSend(page, perPage int) ([]string, *model.AppError) {
    51  	var lines []string
    52  
    53  	if *a.Config().LogSettings.EnableFile {
    54  		file, err := os.Open(utils.GetLogFileLocation(*a.Config().LogSettings.FileLocation))
    55  		if err != nil {
    56  			return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError)
    57  		}
    58  
    59  		defer file.Close()
    60  
    61  		var newLine = []byte{'\n'}
    62  		var lineCount int
    63  		const searchPos = -1
    64  		lineEndPos, err := file.Seek(0, io.SeekEnd)
    65  		if err != nil {
    66  			return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError)
    67  		}
    68  		for {
    69  			pos, err := file.Seek(searchPos, io.SeekCurrent)
    70  			if err != nil {
    71  				return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError)
    72  			}
    73  
    74  			b := make([]byte, 1)
    75  			_, err = file.ReadAt(b, pos)
    76  			if err != nil {
    77  				return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError)
    78  			}
    79  
    80  			if b[0] == newLine[0] || pos == 0 {
    81  				lineCount++
    82  				if lineCount > page*perPage {
    83  					line := make([]byte, lineEndPos-pos)
    84  					_, err := file.ReadAt(line, pos)
    85  					if err != nil {
    86  						return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError)
    87  					}
    88  					lines = append(lines, string(line))
    89  				}
    90  				if pos == 0 {
    91  					break
    92  				}
    93  				lineEndPos = pos
    94  			}
    95  
    96  			if len(lines) == perPage {
    97  				break
    98  			}
    99  		}
   100  
   101  		for i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 {
   102  			lines[i], lines[j] = lines[j], lines[i]
   103  		}
   104  	} else {
   105  		lines = append(lines, "")
   106  	}
   107  
   108  	return lines, nil
   109  }
   110  
   111  func (a *App) GetClusterStatus() []*model.ClusterInfo {
   112  	infos := make([]*model.ClusterInfo, 0)
   113  
   114  	if a.Cluster != nil {
   115  		infos = a.Cluster.GetClusterInfos()
   116  	}
   117  
   118  	return infos
   119  }
   120  
   121  func (a *App) InvalidateAllCaches() *model.AppError {
   122  	debug.FreeOSMemory()
   123  	a.InvalidateAllCachesSkipSend()
   124  
   125  	if a.Cluster != nil {
   126  
   127  		msg := &model.ClusterMessage{
   128  			Event:            model.CLUSTER_EVENT_INVALIDATE_ALL_CACHES,
   129  			SendType:         model.CLUSTER_SEND_RELIABLE,
   130  			WaitForAllToSend: true,
   131  		}
   132  
   133  		a.Cluster.SendClusterMessage(msg)
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  func (a *App) InvalidateAllCachesSkipSend() {
   140  	mlog.Info("Purging all caches")
   141  	a.Srv.sessionCache.Purge()
   142  	ClearStatusCache()
   143  	a.Srv.Store.Channel().ClearCaches()
   144  	a.Srv.Store.User().ClearCaches()
   145  	a.Srv.Store.Post().ClearCaches()
   146  	a.Srv.Store.FileInfo().ClearCaches()
   147  	a.Srv.Store.Webhook().ClearCaches()
   148  	a.LoadLicense()
   149  }
   150  
   151  func (a *App) RecycleDatabaseConnection() {
   152  	oldStore := a.Srv.Store
   153  
   154  	mlog.Warn("Attempting to recycle the database connection.")
   155  	a.Srv.Store = a.Srv.newStore()
   156  	a.Srv.Jobs.Store = a.Srv.Store
   157  
   158  	if a.Srv.Store != oldStore {
   159  		time.Sleep(20 * time.Second)
   160  		oldStore.Close()
   161  	}
   162  
   163  	mlog.Warn("Finished recycling the database connection.")
   164  }
   165  
   166  func (a *App) TestEmail(userId string, cfg *model.Config) *model.AppError {
   167  	if len(*cfg.EmailSettings.SMTPServer) == 0 {
   168  		return model.NewAppError("testEmail", "api.admin.test_email.missing_server", nil, utils.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusBadRequest)
   169  	}
   170  
   171  	// if the user hasn't changed their email settings, fill in the actual SMTP password so that
   172  	// the user can verify an existing SMTP connection
   173  	if *cfg.EmailSettings.SMTPPassword == model.FAKE_SETTING {
   174  		if *cfg.EmailSettings.SMTPServer == *a.Config().EmailSettings.SMTPServer &&
   175  			*cfg.EmailSettings.SMTPPort == *a.Config().EmailSettings.SMTPPort &&
   176  			*cfg.EmailSettings.SMTPUsername == *a.Config().EmailSettings.SMTPUsername {
   177  			*cfg.EmailSettings.SMTPPassword = *a.Config().EmailSettings.SMTPPassword
   178  		} else {
   179  			return model.NewAppError("testEmail", "api.admin.test_email.reenter_password", nil, "", http.StatusBadRequest)
   180  		}
   181  	}
   182  	user, err := a.GetUser(userId)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	T := utils.GetUserTranslations(user.Locale)
   188  	license := a.License()
   189  	if err := mailservice.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), cfg, license != nil && *license.Features.Compliance); err != nil {
   190  		return model.NewAppError("testEmail", "app.admin.test_email.failure", map[string]interface{}{"Error": err.Error()}, "", http.StatusInternalServerError)
   191  	}
   192  
   193  	return nil
   194  }