github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+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 "strings" 10 "time" 11 12 "runtime/debug" 13 14 "net/http" 15 16 l4g "github.com/alecthomas/log4go" 17 "github.com/mattermost/mattermost-server/model" 18 "github.com/mattermost/mattermost-server/store/sqlstore" 19 "github.com/mattermost/mattermost-server/utils" 20 ) 21 22 func (a *App) GetLogs(page, perPage int) ([]string, *model.AppError) { 23 var lines []string 24 if a.Cluster != nil && *a.Config().ClusterSettings.Enable { 25 lines = append(lines, "-----------------------------------------------------------------------------------------------------------") 26 lines = append(lines, "-----------------------------------------------------------------------------------------------------------") 27 lines = append(lines, a.Cluster.GetMyClusterInfo().Hostname) 28 lines = append(lines, "-----------------------------------------------------------------------------------------------------------") 29 lines = append(lines, "-----------------------------------------------------------------------------------------------------------") 30 } 31 32 melines, err := a.GetLogsSkipSend(page, perPage) 33 if err != nil { 34 return nil, err 35 } 36 37 lines = append(lines, melines...) 38 39 if a.Cluster != nil && *a.Config().ClusterSettings.Enable { 40 clines, err := a.Cluster.GetLogs(page, perPage) 41 if err != nil { 42 return nil, err 43 } 44 45 lines = append(lines, clines...) 46 } 47 48 return lines, nil 49 } 50 51 func (a *App) GetLogsSkipSend(page, perPage int) ([]string, *model.AppError) { 52 var lines []string 53 54 if a.Config().LogSettings.EnableFile { 55 file, err := os.Open(utils.GetLogFileLocation(a.Config().LogSettings.FileLocation)) 56 if err != nil { 57 return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) 58 } 59 60 defer file.Close() 61 62 var newLine = []byte{'\n'} 63 var lineCount int 64 const searchPos = -1 65 lineEndPos, err := file.Seek(0, io.SeekEnd) 66 if err != nil { 67 return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) 68 } 69 for { 70 pos, err := file.Seek(searchPos, io.SeekCurrent) 71 if err != nil { 72 return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) 73 } 74 75 b := make([]byte, 1) 76 _, err = file.ReadAt(b, pos) 77 if err != nil { 78 return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) 79 } 80 81 if b[0] == newLine[0] || pos == 0 { 82 lineCount++ 83 if lineCount > page*perPage { 84 line := make([]byte, lineEndPos-pos) 85 _, err := file.ReadAt(line, pos) 86 if err != nil { 87 return nil, model.NewAppError("getLogs", "api.admin.file_read_error", nil, err.Error(), http.StatusInternalServerError) 88 } 89 lines = append(lines, string(line)) 90 } 91 if pos == 0 { 92 break 93 } 94 lineEndPos = pos 95 } 96 97 if len(lines) == perPage { 98 break 99 } 100 } 101 102 for i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 { 103 lines[i], lines[j] = lines[j], lines[i] 104 } 105 } else { 106 lines = append(lines, "") 107 } 108 109 return lines, nil 110 } 111 112 func (a *App) GetClusterStatus() []*model.ClusterInfo { 113 infos := make([]*model.ClusterInfo, 0) 114 115 if a.Cluster != nil { 116 infos = a.Cluster.GetClusterInfos() 117 } 118 119 return infos 120 } 121 122 func (a *App) InvalidateAllCaches() *model.AppError { 123 debug.FreeOSMemory() 124 a.InvalidateAllCachesSkipSend() 125 126 if a.Cluster != nil { 127 128 msg := &model.ClusterMessage{ 129 Event: model.CLUSTER_EVENT_INVALIDATE_ALL_CACHES, 130 SendType: model.CLUSTER_SEND_RELIABLE, 131 WaitForAllToSend: true, 132 } 133 134 a.Cluster.SendClusterMessage(msg) 135 } 136 137 return nil 138 } 139 140 func (a *App) InvalidateAllCachesSkipSend() { 141 l4g.Info(utils.T("api.context.invalidate_all_caches")) 142 a.sessionCache.Purge() 143 ClearStatusCache() 144 sqlstore.ClearChannelCaches() 145 sqlstore.ClearUserCaches() 146 sqlstore.ClearPostCaches() 147 sqlstore.ClearWebhookCaches() 148 a.LoadLicense() 149 } 150 151 func (a *App) GetConfig() *model.Config { 152 json := a.Config().ToJson() 153 cfg := model.ConfigFromJson(strings.NewReader(json)) 154 cfg.Sanitize() 155 156 return cfg 157 } 158 159 func (a *App) SaveConfig(cfg *model.Config, sendConfigChangeClusterMessage bool) *model.AppError { 160 oldCfg := a.Config() 161 cfg.SetDefaults() 162 a.Desanitize(cfg) 163 164 if err := cfg.IsValid(); err != nil { 165 return err 166 } 167 168 if err := utils.ValidateLdapFilter(cfg, a.Ldap); err != nil { 169 return err 170 } 171 172 if *a.Config().ClusterSettings.Enable && *a.Config().ClusterSettings.ReadOnlyConfig { 173 return model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, "", http.StatusForbidden) 174 } 175 176 a.DisableConfigWatch() 177 a.UpdateConfig(func(update *model.Config) { 178 *update = *cfg 179 }) 180 a.PersistConfig() 181 a.ReloadConfig() 182 a.EnableConfigWatch() 183 184 if a.Metrics != nil { 185 if *a.Config().MetricsSettings.Enable { 186 a.Metrics.StartServer() 187 } else { 188 a.Metrics.StopServer() 189 } 190 } 191 192 if a.Cluster != nil { 193 err := a.Cluster.ConfigChanged(cfg, oldCfg, sendConfigChangeClusterMessage) 194 if err != nil { 195 return err 196 } 197 } 198 199 // start/restart email batching job if necessary 200 a.InitEmailBatching() 201 202 return nil 203 } 204 205 func (a *App) RecycleDatabaseConnection() { 206 oldStore := a.Srv.Store 207 208 l4g.Warn(utils.T("api.admin.recycle_db_start.warn")) 209 a.Srv.Store = a.newStore() 210 a.Jobs.Store = a.Srv.Store 211 212 if a.Srv.Store != oldStore { 213 time.Sleep(20 * time.Second) 214 oldStore.Close() 215 } 216 217 l4g.Warn(utils.T("api.admin.recycle_db_end.warn")) 218 } 219 220 func (a *App) TestEmail(userId string, cfg *model.Config) *model.AppError { 221 if len(cfg.EmailSettings.SMTPServer) == 0 { 222 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) 223 } 224 225 // if the user hasn't changed their email settings, fill in the actual SMTP password so that 226 // the user can verify an existing SMTP connection 227 if cfg.EmailSettings.SMTPPassword == model.FAKE_SETTING { 228 if cfg.EmailSettings.SMTPServer == a.Config().EmailSettings.SMTPServer && 229 cfg.EmailSettings.SMTPPort == a.Config().EmailSettings.SMTPPort && 230 cfg.EmailSettings.SMTPUsername == a.Config().EmailSettings.SMTPUsername { 231 cfg.EmailSettings.SMTPPassword = a.Config().EmailSettings.SMTPPassword 232 } else { 233 return model.NewAppError("testEmail", "api.admin.test_email.reenter_password", nil, "", http.StatusBadRequest) 234 } 235 } 236 if user, err := a.GetUser(userId); err != nil { 237 return err 238 } else { 239 T := utils.GetUserTranslations(user.Locale) 240 if err := utils.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), cfg); err != nil { 241 return err 242 } 243 } 244 245 return nil 246 }