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  }