github.com/lologarithm/mattermost-server@v5.3.2-0.20181002060438-c82a84ed765b+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  	"github.com/mattermost/mattermost-server/mlog"
    17  	"github.com/mattermost/mattermost-server/model"
    18  	"github.com/mattermost/mattermost-server/services/mailservice"
    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  	mlog.Info("Purging all caches")
   142  	a.sessionCache.Purge()
   143  	ClearStatusCache()
   144  	a.Srv.Store.Channel().ClearCaches()
   145  	a.Srv.Store.User().ClearCaches()
   146  	a.Srv.Store.Post().ClearCaches()
   147  	a.Srv.Store.FileInfo().ClearCaches()
   148  	a.Srv.Store.Webhook().ClearCaches()
   149  	a.LoadLicense()
   150  }
   151  
   152  func (a *App) GetConfig() *model.Config {
   153  	json := a.Config().ToJson()
   154  	cfg := model.ConfigFromJson(strings.NewReader(json))
   155  	cfg.Sanitize()
   156  
   157  	return cfg
   158  }
   159  
   160  func (a *App) GetEnvironmentConfig() map[string]interface{} {
   161  	return a.EnvironmentConfig()
   162  }
   163  
   164  func (a *App) SaveConfig(cfg *model.Config, sendConfigChangeClusterMessage bool) *model.AppError {
   165  	oldCfg := a.Config()
   166  	cfg.SetDefaults()
   167  	a.Desanitize(cfg)
   168  
   169  	if err := cfg.IsValid(); err != nil {
   170  		return err
   171  	}
   172  
   173  	if err := utils.ValidateLdapFilter(cfg, a.Ldap); err != nil {
   174  		return err
   175  	}
   176  
   177  	if *a.Config().ClusterSettings.Enable && *a.Config().ClusterSettings.ReadOnlyConfig {
   178  		return model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, "", http.StatusForbidden)
   179  	}
   180  
   181  	a.DisableConfigWatch()
   182  
   183  	a.UpdateConfig(func(update *model.Config) {
   184  		*update = *cfg
   185  	})
   186  	a.PersistConfig()
   187  	a.ReloadConfig()
   188  	a.EnableConfigWatch()
   189  
   190  	if a.Metrics != nil {
   191  		if *a.Config().MetricsSettings.Enable {
   192  			a.Metrics.StartServer()
   193  		} else {
   194  			a.Metrics.StopServer()
   195  		}
   196  	}
   197  
   198  	if a.Cluster != nil {
   199  		err := a.Cluster.ConfigChanged(cfg, oldCfg, sendConfigChangeClusterMessage)
   200  		if err != nil {
   201  			return err
   202  		}
   203  	}
   204  
   205  	// start/restart email batching job if necessary
   206  	a.InitEmailBatching()
   207  
   208  	return nil
   209  }
   210  
   211  func (a *App) RecycleDatabaseConnection() {
   212  	oldStore := a.Srv.Store
   213  
   214  	mlog.Warn("Attempting to recycle the database connection.")
   215  	a.Srv.Store = a.newStore()
   216  	a.Jobs.Store = a.Srv.Store
   217  
   218  	if a.Srv.Store != oldStore {
   219  		time.Sleep(20 * time.Second)
   220  		oldStore.Close()
   221  	}
   222  
   223  	mlog.Warn("Finished recycling the database connection.")
   224  }
   225  
   226  func (a *App) TestEmail(userId string, cfg *model.Config) *model.AppError {
   227  	if len(cfg.EmailSettings.SMTPServer) == 0 {
   228  		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)
   229  	}
   230  
   231  	// if the user hasn't changed their email settings, fill in the actual SMTP password so that
   232  	// the user can verify an existing SMTP connection
   233  	if cfg.EmailSettings.SMTPPassword == model.FAKE_SETTING {
   234  		if cfg.EmailSettings.SMTPServer == a.Config().EmailSettings.SMTPServer &&
   235  			cfg.EmailSettings.SMTPPort == a.Config().EmailSettings.SMTPPort &&
   236  			cfg.EmailSettings.SMTPUsername == a.Config().EmailSettings.SMTPUsername {
   237  			cfg.EmailSettings.SMTPPassword = a.Config().EmailSettings.SMTPPassword
   238  		} else {
   239  			return model.NewAppError("testEmail", "api.admin.test_email.reenter_password", nil, "", http.StatusBadRequest)
   240  		}
   241  	}
   242  	user, err := a.GetUser(userId)
   243  	if err != nil {
   244  		return err
   245  	}
   246  
   247  	T := utils.GetUserTranslations(user.Locale)
   248  	license := a.License()
   249  	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 {
   250  		return model.NewAppError("testEmail", "app.admin.test_email.failure", map[string]interface{}{"Error": err.Error()}, "", http.StatusInternalServerError)
   251  	}
   252  
   253  	return nil
   254  }