github.com/gigforks/mattermost-server@v4.9.1-0.20180619094218-800d97fa55d0+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/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.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) 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) GetEnvironmentConfig() map[string]interface{} {
   160  	return a.EnvironmentConfig()
   161  }
   162  
   163  func (a *App) SaveConfig(cfg *model.Config, sendConfigChangeClusterMessage bool) *model.AppError {
   164  	oldCfg := a.Config()
   165  	cfg.SetDefaults()
   166  	a.Desanitize(cfg)
   167  
   168  	if err := cfg.IsValid(); err != nil {
   169  		return err
   170  	}
   171  
   172  	if err := utils.ValidateLdapFilter(cfg, a.Ldap); err != nil {
   173  		return err
   174  	}
   175  
   176  	if *a.Config().ClusterSettings.Enable && *a.Config().ClusterSettings.ReadOnlyConfig {
   177  		return model.NewAppError("saveConfig", "ent.cluster.save_config.error", nil, "", http.StatusForbidden)
   178  	}
   179  
   180  	a.DisableConfigWatch()
   181  	a.UpdateConfig(func(update *model.Config) {
   182  		*update = *cfg
   183  	})
   184  	a.PersistConfig()
   185  	a.ReloadConfig()
   186  	a.EnableConfigWatch()
   187  
   188  	if a.Metrics != nil {
   189  		if *a.Config().MetricsSettings.Enable {
   190  			a.Metrics.StartServer()
   191  		} else {
   192  			a.Metrics.StopServer()
   193  		}
   194  	}
   195  
   196  	if a.Cluster != nil {
   197  		err := a.Cluster.ConfigChanged(cfg, oldCfg, sendConfigChangeClusterMessage)
   198  		if err != nil {
   199  			return err
   200  		}
   201  	}
   202  
   203  	// start/restart email batching job if necessary
   204  	a.InitEmailBatching()
   205  
   206  	return nil
   207  }
   208  
   209  func (a *App) RecycleDatabaseConnection() {
   210  	oldStore := a.Srv.Store
   211  
   212  	mlog.Warn("Attempting to recycle the database connection.")
   213  	a.Srv.Store = a.newStore()
   214  	a.Jobs.Store = a.Srv.Store
   215  
   216  	if a.Srv.Store != oldStore {
   217  		time.Sleep(20 * time.Second)
   218  		oldStore.Close()
   219  	}
   220  
   221  	mlog.Warn("Finished recycling the database connection.")
   222  }
   223  
   224  func (a *App) TestEmail(userId string, cfg *model.Config) *model.AppError {
   225  	if len(cfg.EmailSettings.SMTPServer) == 0 {
   226  		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)
   227  	}
   228  
   229  	// if the user hasn't changed their email settings, fill in the actual SMTP password so that
   230  	// the user can verify an existing SMTP connection
   231  	if cfg.EmailSettings.SMTPPassword == model.FAKE_SETTING {
   232  		if cfg.EmailSettings.SMTPServer == a.Config().EmailSettings.SMTPServer &&
   233  			cfg.EmailSettings.SMTPPort == a.Config().EmailSettings.SMTPPort &&
   234  			cfg.EmailSettings.SMTPUsername == a.Config().EmailSettings.SMTPUsername {
   235  			cfg.EmailSettings.SMTPPassword = a.Config().EmailSettings.SMTPPassword
   236  		} else {
   237  			return model.NewAppError("testEmail", "api.admin.test_email.reenter_password", nil, "", http.StatusBadRequest)
   238  		}
   239  	}
   240  	if user, err := a.GetUser(userId); err != nil {
   241  		return err
   242  	} else {
   243  		T := utils.GetUserTranslations(user.Locale)
   244  		license := a.License()
   245  		if err := utils.SendMailUsingConfig(user.Email, T("api.admin.test_email.subject"), T("api.admin.test_email.body"), cfg, license != nil && *license.Features.Compliance); err != nil {
   246  			return model.NewAppError("testEmail", "app.admin.test_email.failure", map[string]interface{}{"Error": err.Error()}, "", http.StatusInternalServerError)
   247  		}
   248  	}
   249  
   250  	return nil
   251  }