in internal/cli/praefect/subcmd_dataloss.go [60:185]
func datalossAction(ctx context.Context, cmd *cli.Command) error {
logger := log.ConfigureCommand()
conf, err := readConfig(cmd.String(configFlagName))
if err != nil {
return err
}
includePartiallyAvailable := cmd.Bool("partially-unavailable")
virtualStorages := []string{cmd.String(paramVirtualStorage)}
if virtualStorages[0] == "" {
virtualStorages = make([]string, len(conf.VirtualStorages))
for i := range conf.VirtualStorages {
virtualStorages[i] = conf.VirtualStorages[i].Name
}
}
sort.Strings(virtualStorages)
nodeAddr, err := getNodeAddress(conf)
if err != nil {
return err
}
conn, err := subCmdDial(ctx, nodeAddr, conf.Auth.Token, defaultDialTimeout)
if err != nil {
return fmt.Errorf("error dialing: %w", err)
}
defer func() {
if err := conn.Close(); err != nil {
logger.WithError(err).Info("error closing connection")
}
}()
client := gitalypb.NewPraefectInfoServiceClient(conn)
for _, vs := range virtualStorages {
stream, err := client.Dataloss(ctx, &gitalypb.DatalossRequest{
VirtualStorage: vs,
IncludePartiallyReplicated: includePartiallyAvailable,
})
if err != nil {
return fmt.Errorf("error checking: %w", err)
}
var foundUnavailableRepos bool
indentPrintln(cmd.Writer, 0, "Virtual storage: %s", vs)
for {
resp, err := stream.Recv()
if err != nil {
if !errors.Is(err, io.EOF) {
return fmt.Errorf("getting response: %w", err)
}
break
}
if len(resp.GetRepositories()) > 0 {
indentPrintln(cmd.Writer, 1, "Repositories:")
}
for _, repo := range resp.GetRepositories() {
foundUnavailableRepos = true
unavailable := ""
if repo.GetUnavailable() {
unavailable = " (unavailable)"
}
indentPrintln(cmd.Writer, 2, "%s%s:", repo.GetRelativePath(), unavailable)
primary := repo.GetPrimary()
if primary == "" {
primary = "No Primary"
}
indentPrintln(cmd.Writer, 3, "Primary: %s", primary)
indentPrintln(cmd.Writer, 3, "In-Sync Storages:")
for _, storage := range repo.GetStorages() {
if storage.GetBehindBy() != 0 {
continue
}
indentPrintln(cmd.Writer, 4, "%s%s%s",
storage.GetName(),
assignedMessage(storage.GetAssigned()),
unhealthyMessage(storage.GetHealthy()),
)
}
indentPrintln(cmd.Writer, 3, "Outdated Storages:")
for _, storage := range repo.GetStorages() {
if storage.GetBehindBy() == 0 {
continue
}
plural := ""
if storage.GetBehindBy() > 1 {
plural = "s"
}
indentPrintln(cmd.Writer, 4, "%s is behind by %d change%s or less%s%s",
storage.GetName(),
storage.GetBehindBy(),
plural,
assignedMessage(storage.GetAssigned()),
unhealthyMessage(storage.GetHealthy()),
)
}
}
}
if !foundUnavailableRepos {
msg := "All repositories are available!"
if includePartiallyAvailable {
msg = "All repositories are fully available on all assigned storages!"
}
indentPrintln(cmd.Writer, 1, "%s", msg)
continue
}
}
return nil
}