Add integrity check command to CLI (#11599)
* Add integrity command * Add structures and implementation for basic referential integrity check * Use a channel to receive integrity check reports as they generates * Setup unit testing * Add confirm prompt to integrity command and make verbose output optional * Add more integrity checks * Use wrapper functions to simplify behaviour and tests * Improve extensibility of IntegrityCheckResult * Improve CheckIntegrity tests performance * Use a config structure for relational integrity checks * Add more relational integrity checks * Add more checks and do some cleanup * Add more relational integrity checks with proper tests * Fix tests to use sync functions * Add more info to integrity command help * Add more relational integrity checks * Add more relational integrity checks * Add missing checks * Show more information about missing records * Fix to use new sync function * Change integrity check functions to accept a SqlSupplier * Fix code duplication * Use squirrel for query building
Этот коммит содержится в:
коммит произвёл
Jesse Hallam
родитель
d1f0216c22
Коммит
e1eb839636
78
cmd/mattermost/commands/integrity.go
Обычный файл
78
cmd/mattermost/commands/integrity.go
Обычный файл
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/store"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var IntegrityCmd = &cobra.Command{
|
||||
Use: "integrity",
|
||||
Short: "Check database data integrity",
|
||||
RunE: integrityCmdF,
|
||||
}
|
||||
|
||||
func init() {
|
||||
IntegrityCmd.Flags().Bool("confirm", false, "Confirm you really want to run a complete integrity check that may temporarily harm system performance")
|
||||
IntegrityCmd.Flags().BoolP("verbose", "v", false, "Show detailed information on integrity check results")
|
||||
RootCmd.AddCommand(IntegrityCmd)
|
||||
}
|
||||
|
||||
func printRelationalIntegrityCheckResult(data store.RelationalIntegrityCheckData, verbose bool) {
|
||||
fmt.Println(fmt.Sprintf("Found %d records in relation %s orphans of relation %s",
|
||||
len(data.Records), data.ChildName, data.ParentName))
|
||||
if !verbose {
|
||||
return
|
||||
}
|
||||
for _, record := range data.Records {
|
||||
if record.ChildId != "" {
|
||||
fmt.Println(fmt.Sprintf(" Child %s (%s.%s) is missing Parent %s (%s.%s)", record.ChildId, data.ChildName, data.ChildIdAttr, record.ParentId, data.ChildName, data.ParentIdAttr))
|
||||
} else {
|
||||
fmt.Println(fmt.Sprintf(" Child is missing Parent %s (%s.%s)", record.ParentId, data.ChildName, data.ParentIdAttr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printIntegrityCheckResult(result store.IntegrityCheckResult, verbose bool) {
|
||||
switch data := result.Data.(type) {
|
||||
case store.RelationalIntegrityCheckData:
|
||||
printRelationalIntegrityCheckResult(data, verbose)
|
||||
}
|
||||
}
|
||||
|
||||
func integrityCmdF(command *cobra.Command, args []string) error {
|
||||
a, err := InitDBCommandContextCobra(command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer a.Shutdown()
|
||||
|
||||
confirmFlag, _ := command.Flags().GetBool("confirm")
|
||||
if !confirmFlag {
|
||||
var confirm string
|
||||
fmt.Fprintf(os.Stdout, "This check may harm performance on live systems. Are you sure you want to proceed? (y/N): ")
|
||||
fmt.Scanln(&confirm)
|
||||
if !strings.EqualFold(confirm, "y") && !strings.EqualFold(confirm, "yes") {
|
||||
fmt.Fprintf(os.Stderr, "Aborted.\n")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
verboseFlag, _ := command.Flags().GetBool("verbose")
|
||||
results := a.Srv.Store.CheckIntegrity()
|
||||
for result := range results {
|
||||
if result.Err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", result.Err.Error())
|
||||
break
|
||||
}
|
||||
printIntegrityCheckResult(result, verboseFlag)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -217,6 +217,10 @@ func (s *LayeredStore) TotalSearchDbConnections() int {
|
||||
return s.DatabaseLayer.TotalSearchDbConnections()
|
||||
}
|
||||
|
||||
func (s *LayeredStore) CheckIntegrity() <-chan IntegrityCheckResult {
|
||||
return s.DatabaseLayer.CheckIntegrity()
|
||||
}
|
||||
|
||||
type LayeredRoleStore struct {
|
||||
*LayeredStore
|
||||
}
|
||||
|
||||
514
store/sqlstore/integrity.go
Обычный файл
514
store/sqlstore/integrity.go
Обычный файл
@@ -0,0 +1,514 @@
|
||||
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/mlog"
|
||||
"github.com/mattermost/mattermost-server/store"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
)
|
||||
|
||||
type relationalCheckConfig struct {
|
||||
parentName string
|
||||
parentIdAttr string
|
||||
childName string
|
||||
childIdAttr string
|
||||
canParentIdBeEmpty bool
|
||||
sortRecords bool
|
||||
}
|
||||
|
||||
func getOrphanedRecords(ss *SqlSupplier, cfg relationalCheckConfig) ([]store.OrphanedRecord, error) {
|
||||
var records []store.OrphanedRecord
|
||||
|
||||
sub := ss.getQueryBuilder().
|
||||
Select("TRUE").
|
||||
From(cfg.parentName).
|
||||
Prefix("NOT EXISTS (").
|
||||
Suffix(")").
|
||||
Where(sq.Eq{"id": cfg.childName + "." + cfg.parentIdAttr})
|
||||
|
||||
main := ss.getQueryBuilder().
|
||||
Select().
|
||||
Column(cfg.parentIdAttr + " AS ParentId").
|
||||
From(cfg.childName).
|
||||
Where(sub)
|
||||
|
||||
if cfg.childIdAttr != "" {
|
||||
main = main.Column(cfg.childIdAttr + " AS ChildId")
|
||||
}
|
||||
|
||||
if cfg.canParentIdBeEmpty {
|
||||
main = main.Where(sq.NotEq{cfg.parentIdAttr: ""})
|
||||
}
|
||||
|
||||
if cfg.sortRecords {
|
||||
main = main.OrderBy(cfg.parentIdAttr)
|
||||
}
|
||||
|
||||
query, args, _ := main.ToSql()
|
||||
_, err := ss.GetMaster().Select(&records, query, args...)
|
||||
|
||||
return records, err
|
||||
}
|
||||
|
||||
func checkParentChildIntegrity(ss *SqlSupplier, config relationalCheckConfig) store.IntegrityCheckResult {
|
||||
var result store.IntegrityCheckResult
|
||||
var data store.RelationalIntegrityCheckData
|
||||
|
||||
config.sortRecords = true
|
||||
data.Records, result.Err = getOrphanedRecords(ss, config)
|
||||
if result.Err != nil {
|
||||
mlog.Error(result.Err.Error())
|
||||
return result
|
||||
}
|
||||
data.ParentName = config.parentName
|
||||
data.ChildName = config.childName
|
||||
data.ParentIdAttr = config.parentIdAttr
|
||||
data.ChildIdAttr = config.childIdAttr
|
||||
result.Data = data
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func checkChannelsCommandWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Channels",
|
||||
parentIdAttr: "ChannelId",
|
||||
childName: "CommandWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkChannelsChannelMemberHistoryIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Channels",
|
||||
parentIdAttr: "ChannelId",
|
||||
childName: "ChannelMemberHistory",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkChannelsChannelMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Channels",
|
||||
parentIdAttr: "ChannelId",
|
||||
childName: "ChannelMembers",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkChannelsIncomingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Channels",
|
||||
parentIdAttr: "ChannelId",
|
||||
childName: "IncomingWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkChannelsOutgoingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Channels",
|
||||
parentIdAttr: "ChannelId",
|
||||
childName: "OutgoingWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkChannelsPostsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Channels",
|
||||
parentIdAttr: "ChannelId",
|
||||
childName: "Posts",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkCommandsCommandWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Commands",
|
||||
parentIdAttr: "CommandId",
|
||||
childName: "CommandWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkPostsFileInfoIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Posts",
|
||||
parentIdAttr: "PostId",
|
||||
childName: "FileInfo",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkPostsPostsParentIdIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Posts",
|
||||
parentIdAttr: "ParentId",
|
||||
childName: "Posts",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkPostsPostsRootIdIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Posts",
|
||||
parentIdAttr: "RootId",
|
||||
childName: "Posts",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkPostsReactionsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Posts",
|
||||
parentIdAttr: "PostId",
|
||||
childName: "Reactions",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkSchemesChannelsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Schemes",
|
||||
parentIdAttr: "SchemeId",
|
||||
childName: "Channels",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkSchemesTeamsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Schemes",
|
||||
parentIdAttr: "SchemeId",
|
||||
childName: "Teams",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkSessionsAuditsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Sessions",
|
||||
parentIdAttr: "SessionId",
|
||||
childName: "Audits",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkTeamsChannelsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Teams",
|
||||
parentIdAttr: "TeamId",
|
||||
childName: "Channels",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkTeamsCommandsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Teams",
|
||||
parentIdAttr: "TeamId",
|
||||
childName: "Commands",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkTeamsIncomingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Teams",
|
||||
parentIdAttr: "TeamId",
|
||||
childName: "IncomingWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkTeamsOutgoingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Teams",
|
||||
parentIdAttr: "TeamId",
|
||||
childName: "OutgoingWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkTeamsTeamMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Teams",
|
||||
parentIdAttr: "TeamId",
|
||||
childName: "TeamMembers",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersAuditsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Audits",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersCommandWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "CommandWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersChannelMemberHistoryIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "ChannelMemberHistory",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersChannelMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "ChannelMembers",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersChannelsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "CreatorId",
|
||||
childName: "Channels",
|
||||
childIdAttr: "Id",
|
||||
canParentIdBeEmpty: true,
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersCommandsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "CreatorId",
|
||||
childName: "Commands",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersCompliancesIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Compliances",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersEmojiIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "CreatorId",
|
||||
childName: "Emoji",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersFileInfoIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Posts",
|
||||
parentIdAttr: "CreatorId",
|
||||
childName: "FileInfo",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersIncomingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "IncomingWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersOAuthAccessDataIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "OAuthAccessData",
|
||||
childIdAttr: "Token",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersOAuthAppsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "CreatorId",
|
||||
childName: "OAuthApps",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersOAuthAuthDataIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "OAuthAuthData",
|
||||
childIdAttr: "Code",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersOutgoingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "CreatorId",
|
||||
childName: "OutgoingWebhooks",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersPostsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Posts",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersPreferencesIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Preferences",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersReactionsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Reactions",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersSessionsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Sessions",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersStatusIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "Status",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersTeamMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "TeamMembers",
|
||||
childIdAttr: "",
|
||||
})
|
||||
}
|
||||
|
||||
func checkUsersUserAccessTokensIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
|
||||
return checkParentChildIntegrity(ss, relationalCheckConfig{
|
||||
parentName: "Users",
|
||||
parentIdAttr: "UserId",
|
||||
childName: "UserAccessTokens",
|
||||
childIdAttr: "Id",
|
||||
})
|
||||
}
|
||||
|
||||
func checkChannelsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkChannelsCommandWebhooksIntegrity(ss)
|
||||
results <- checkChannelsChannelMemberHistoryIntegrity(ss)
|
||||
results <- checkChannelsChannelMembersIntegrity(ss)
|
||||
results <- checkChannelsIncomingWebhooksIntegrity(ss)
|
||||
results <- checkChannelsOutgoingWebhooksIntegrity(ss)
|
||||
results <- checkChannelsPostsIntegrity(ss)
|
||||
}
|
||||
|
||||
func checkCommandsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkCommandsCommandWebhooksIntegrity(ss)
|
||||
}
|
||||
|
||||
func checkPostsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkPostsFileInfoIntegrity(ss)
|
||||
results <- checkPostsPostsParentIdIntegrity(ss)
|
||||
results <- checkPostsPostsRootIdIntegrity(ss)
|
||||
results <- checkPostsReactionsIntegrity(ss)
|
||||
}
|
||||
|
||||
func checkSchemesIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkSchemesChannelsIntegrity(ss)
|
||||
results <- checkSchemesTeamsIntegrity(ss)
|
||||
}
|
||||
|
||||
func checkSessionsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkSessionsAuditsIntegrity(ss)
|
||||
}
|
||||
|
||||
func checkTeamsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkTeamsChannelsIntegrity(ss)
|
||||
results <- checkTeamsCommandsIntegrity(ss)
|
||||
results <- checkTeamsIncomingWebhooksIntegrity(ss)
|
||||
results <- checkTeamsOutgoingWebhooksIntegrity(ss)
|
||||
results <- checkTeamsTeamMembersIntegrity(ss)
|
||||
}
|
||||
|
||||
func checkUsersIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
results <- checkUsersAuditsIntegrity(ss)
|
||||
results <- checkUsersCommandWebhooksIntegrity(ss)
|
||||
results <- checkUsersChannelMemberHistoryIntegrity(ss)
|
||||
results <- checkUsersChannelMembersIntegrity(ss)
|
||||
results <- checkUsersChannelsIntegrity(ss)
|
||||
results <- checkUsersCommandsIntegrity(ss)
|
||||
results <- checkUsersCompliancesIntegrity(ss)
|
||||
results <- checkUsersEmojiIntegrity(ss)
|
||||
results <- checkUsersFileInfoIntegrity(ss)
|
||||
results <- checkUsersIncomingWebhooksIntegrity(ss)
|
||||
results <- checkUsersOAuthAccessDataIntegrity(ss)
|
||||
results <- checkUsersOAuthAppsIntegrity(ss)
|
||||
results <- checkUsersOAuthAuthDataIntegrity(ss)
|
||||
results <- checkUsersOutgoingWebhooksIntegrity(ss)
|
||||
results <- checkUsersPostsIntegrity(ss)
|
||||
results <- checkUsersPreferencesIntegrity(ss)
|
||||
results <- checkUsersReactionsIntegrity(ss)
|
||||
results <- checkUsersSessionsIntegrity(ss)
|
||||
results <- checkUsersStatusIntegrity(ss)
|
||||
results <- checkUsersTeamMembersIntegrity(ss)
|
||||
results <- checkUsersUserAccessTokensIntegrity(ss)
|
||||
}
|
||||
|
||||
func CheckRelationalIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
|
||||
mlog.Info("Starting relational integrity checks...")
|
||||
checkChannelsIntegrity(ss, results)
|
||||
checkCommandsIntegrity(ss, results)
|
||||
checkPostsIntegrity(ss, results)
|
||||
checkSchemesIntegrity(ss, results)
|
||||
checkSessionsIntegrity(ss, results)
|
||||
checkTeamsIntegrity(ss, results)
|
||||
checkUsersIntegrity(ss, results)
|
||||
mlog.Info("Done with relational integrity checks")
|
||||
close(results)
|
||||
}
|
||||
1539
store/sqlstore/integrity_test.go
Обычный файл
1539
store/sqlstore/integrity_test.go
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -1066,6 +1066,12 @@ func (ss *SqlSupplier) getQueryBuilder() sq.StatementBuilderType {
|
||||
return builder
|
||||
}
|
||||
|
||||
func (ss *SqlSupplier) CheckIntegrity() <-chan store.IntegrityCheckResult {
|
||||
results := make(chan store.IntegrityCheckResult)
|
||||
go CheckRelationalIntegrity(ss, results)
|
||||
return results
|
||||
}
|
||||
|
||||
type mattermConverter struct{}
|
||||
|
||||
func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {
|
||||
|
||||
@@ -55,6 +55,7 @@ type Store interface {
|
||||
TotalMasterDbConnections() int
|
||||
TotalReadDbConnections() int
|
||||
TotalSearchDbConnections() int
|
||||
CheckIntegrity() <-chan IntegrityCheckResult
|
||||
}
|
||||
|
||||
type TeamStore interface {
|
||||
@@ -627,3 +628,21 @@ type UserGetByIdsOpts struct {
|
||||
// Since filters the users based on their UpdateAt timestamp.
|
||||
Since int64
|
||||
}
|
||||
|
||||
type OrphanedRecord struct {
|
||||
ParentId string
|
||||
ChildId string
|
||||
}
|
||||
|
||||
type RelationalIntegrityCheckData struct {
|
||||
ParentName string
|
||||
ChildName string
|
||||
ParentIdAttr string
|
||||
ChildIdAttr string
|
||||
Records []OrphanedRecord
|
||||
}
|
||||
|
||||
type IntegrityCheckResult struct {
|
||||
Data interface{}
|
||||
Err error
|
||||
}
|
||||
|
||||
@@ -78,6 +78,22 @@ func (_m *LayeredStoreDatabaseLayer) ChannelMemberHistory() store.ChannelMemberH
|
||||
return r0
|
||||
}
|
||||
|
||||
// CheckIntegrity provides a mock function with given fields:
|
||||
func (_m *LayeredStoreDatabaseLayer) CheckIntegrity() <-chan store.IntegrityCheckResult {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 <-chan store.IntegrityCheckResult
|
||||
if rf, ok := ret.Get(0).(func() <-chan store.IntegrityCheckResult); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(<-chan store.IntegrityCheckResult)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *LayeredStoreDatabaseLayer) Close() {
|
||||
_m.Called()
|
||||
|
||||
@@ -76,6 +76,22 @@ func (_m *Store) ChannelMemberHistory() store.ChannelMemberHistoryStore {
|
||||
return r0
|
||||
}
|
||||
|
||||
// CheckIntegrity provides a mock function with given fields:
|
||||
func (_m *Store) CheckIntegrity() <-chan store.IntegrityCheckResult {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 <-chan store.IntegrityCheckResult
|
||||
if rf, ok := ret.Get(0).(func() <-chan store.IntegrityCheckResult); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(<-chan store.IntegrityCheckResult)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Close provides a mock function with given fields:
|
||||
func (_m *Store) Close() {
|
||||
_m.Called()
|
||||
|
||||
@@ -87,6 +87,9 @@ func (s *Store) TotalMasterDbConnections() int { return 1 }
|
||||
func (s *Store) TotalReadDbConnections() int { return 1 }
|
||||
func (s *Store) TotalSearchDbConnections() int { return 1 }
|
||||
func (s *Store) GetCurrentSchemaVersion() string { return "" }
|
||||
func (s *Store) CheckIntegrity() <-chan store.IntegrityCheckResult {
|
||||
return make(chan store.IntegrityCheckResult)
|
||||
}
|
||||
|
||||
func (s *Store) AssertExpectations(t mock.TestingT) bool {
|
||||
return mock.AssertExpectationsForObjects(t,
|
||||
|
||||
Ссылка в новой задаче
Block a user