func datalossAction()

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
}