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
|
||||
}
|
||||
Ссылка в новой задаче
Block a user