[MM-63556] mmctl: Add compliance export download cmd (#30576)

* add mmctl compliance export download command and tests

- Introduced `ComplianceExportDownloadCmd` to facilitate downloading compliance export files.
- Implemented the `DownloadComplianceExport` method in the Client interface for handling file downloads.
- Added unit tests for the download command, covering successful downloads, error handling for non-existent jobs, and retries on failure.
- Included end-to-end tests to validate the command's functionality.
- Updated documentation to include usage examples and options for the new command.

* don't know why this was left out

* PR comments

* adjust test for new retry logic

* refactored download fn for compliance_export and export

* fix test due to fixed logic

* docs
Этот коммит содержится в:
Christopher Poile
2025-06-24 16:27:54 -04:00
коммит произвёл GitHub
родитель 60a747f975
Коммит b33a7e362f
12 изменённых файлов: 548 добавлений и 22 удалений

Просмотреть файл

@@ -225,15 +225,36 @@ func exportDownloadCmdF(c client.Client, command *cobra.Command, args []string)
retries, _ := command.Flags().GetInt("num-retries")
downloadFn := func(outFile *os.File) (string, error) {
off, err := outFile.Seek(0, io.SeekEnd)
if err != nil {
return "", fmt.Errorf("failed to seek file: %w", err)
}
_, _, err = c.DownloadExport(context.TODO(), name, outFile, off)
return "", err
}
_, err := downloadFile(path, downloadFn, retries, "export")
if err != nil {
return err
}
printer.Print(fmt.Sprintf("Export file downloaded to %q", path))
return nil
}
// downloadFile handles the common logic for downloading files in export and compliance_export commands
func downloadFile(path string, downloadFn func(*os.File) (string, error), retries int, fileType string) (string, error) {
var outFile *os.File
info, err := os.Stat(path)
switch {
case err != nil && !os.IsNotExist(err):
// some error occurred and not because file doesn't exist
return fmt.Errorf("failed to stat export file: %w", err)
return "", fmt.Errorf("failed to stat %s file: %w", fileType, err)
case err == nil && info.Size() > 0:
// we exit to avoid overwriting an existing non-empty file
return fmt.Errorf("export file already exists")
return "", fmt.Errorf("%s file already exists", fileType)
case err != nil:
// file does not exist, we create it
outFile, err = os.Create(path)
@@ -243,30 +264,24 @@ func exportDownloadCmdF(c client.Client, command *cobra.Command, args []string)
}
if err != nil {
return fmt.Errorf("failed to create/open export file: %w", err)
return "", fmt.Errorf("failed to create/open %s file: %w", fileType, err)
}
defer outFile.Close()
i := 0
for i < retries+1 {
off, err := outFile.Seek(0, io.SeekEnd)
var suggestedFilename string
for i := range retries + 1 { // need to include the first attempt
suggestedFilename, err = downloadFn(outFile)
if err != nil {
return fmt.Errorf("failed to seek export file: %w", err)
}
if _, _, err := c.DownloadExport(context.TODO(), name, outFile, off); err != nil {
printer.PrintWarning(fmt.Sprintf("failed to download export file: %v. Retrying...", err))
i++
if i >= retries {
return "", fmt.Errorf("failed to download %s after %d retries: %w", fileType, retries, err)
}
printer.PrintWarning(fmt.Sprintf("Download attempt %d/%d failed. Retrying...", i+1, retries+1))
continue
}
break
}
if retries != 0 && i == retries+1 {
return fmt.Errorf("failed to download export after %d retries", retries)
}
return nil
return suggestedFilename, nil
}
func exportJobListCmdF(c client.Client, command *cobra.Command, args []string) error {