diff --git a/pkg/debug/chart.go b/pkg/debug/chart.go index c7ef318a..803ec0d1 100644 --- a/pkg/debug/chart.go +++ b/pkg/debug/chart.go @@ -15,136 +15,156 @@ import ( "github.com/spf13/cobra" ) +var ( + chartOnly bool +) + func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { chartDebug := &cobra.Command{ Use: "debug-chart", Short: "This command helps debug the internal chart files", - Run: func(cmd *cobra.Command, _ []string) { - chartOnly, _ := cmd.Flags().GetBool("chart-only") + RunE: func(_ *cobra.Command, _ []string) error { if chartOnly { logrus.Info("Only the embedded chart's `Chart.yaml` will be exported.") } else { logrus.Info("The entire embedded chart wil be exported.") } - chartTarballData, err := base64.StdEncoding.DecodeString(base64ChartTarball) + tarReader, err := readEmbeddedHelmChart(base64ChartTarball) if err != nil { - fmt.Println("error:", err) - return + return err } - gzipReader, err := gzip.NewReader(bytes.NewReader(chartTarballData)) - if err != nil { - fmt.Println("Error creating gzip reader:", err) - return - } - defer gzipReader.Close() - - // Create a tar reader - tarReader := tar.NewReader(gzipReader) - // Extract files to the current working directory cwd, err := os.Getwd() if err != nil { - fmt.Println("Error getting current working directory:", err) - return + return fmt.Errorf("error getting current working directory: %v", err) } debugDir := filepath.Join(cwd, ".debug") // Ensure the .debug directory exists if err := os.MkdirAll(debugDir, 0755); err != nil { - fmt.Println("Error creating .debug directory:", err) - return + return fmt.Errorf("error creating .debug directory: %v", err) } - // Extract files to the .debug directory - for { - header, err := tarReader.Next() - if err == io.EOF { - // End of archive - break - } - if err != nil { - fmt.Println("Error reading tarball:", err) - return - } - - // Determine the path to extract the file to - filePath := filepath.Join(debugDir, header.Name) - - if chartOnly { - switch header.Typeflag { - case tar.TypeReg: - if header.Name == "rancher-project-monitoring/Chart.yaml" { - logrus.Info("Found a `Chart.yaml` file to export.") - // Ensure the parent directory exists - parentDir := filepath.Dir(filePath) - if err := os.MkdirAll(parentDir, 0755); err != nil { - logrus.Error("Error creating parent directory:", err) - return - } - - // Create regular file - outFile, err := os.Create(filePath) - if err != nil { - logrus.Error("Error creating file:", err) - return - } - - // Copy file content - if _, err := io.Copy(outFile, tarReader); err != nil { - logrus.Error("Error writing file content:", err) - outFile.Close() - return - } - logrus.Info("The `Chart.yaml` file was exported") - outFile.Close() - } else { - logrus.Debugf("Skipping file: %s\n", header.Name) - } - default: - logrus.Debugf("Skipping file: %s\n", header.Name) - } - - return - } - - switch header.Typeflag { - case tar.TypeDir: - // Create directory - if err := os.MkdirAll(filePath, os.FileMode(header.Mode)); err != nil { - fmt.Println("Error creating directory:", err) - return - } - case tar.TypeReg: - // Ensure the parent directory exists - parentDir := filepath.Dir(filePath) - if err := os.MkdirAll(parentDir, 0755); err != nil { - fmt.Println("Error creating parent directory:", err) - return - } - - // Create regular file - outFile, err := os.Create(filePath) - if err != nil { - fmt.Println("Error creating file:", err) - return - } - - // Copy file content - if _, err := io.Copy(outFile, tarReader); err != nil { - fmt.Println("Error writing file content:", err) - outFile.Close() - return - } - outFile.Close() - default: - fmt.Printf("Skipping unsupported file type: %s\n", header.Name) - } + err = extractChartData(tarReader, debugDir, chartOnly) + if err != nil { + return err } - fmt.Println("Chart files successfully extracted to", debugDir) + logrus.Infof("Chart files successfully extracted to: %s", debugDir) + return nil }, } - chartDebug.PersistentFlags().BoolP("chart-only", "C", false, "When set, only the `Chart.yaml` will be exported.") + chartDebug.Flags().BoolVarP(&chartOnly, "chart-only", "C", false, "When set, only the `Chart.yaml` will be exported.") return chartDebug } + +func readEmbeddedHelmChart(base64ChartTarball string) (*tar.Reader, error) { + chartTarballData, err := base64.StdEncoding.DecodeString(base64ChartTarball) + if err != nil { + return nil, fmt.Errorf("error reading embedded chart data from base64: %v", err) + } + + gzipReader, err := gzip.NewReader(bytes.NewReader(chartTarballData)) + if err != nil { + return nil, fmt.Errorf("error creating gzip reader: %v", err) + } + defer gzipReader.Close() + + // Create a tar reader + tarReader := tar.NewReader(gzipReader) + return tarReader, nil +} + +func extractChartData(tarReader *tar.Reader, debugDir string, chartOnly bool) error { + // Extract files to the .debug directory + for { + header, err := tarReader.Next() + if err == io.EOF { + // End of archive + break + } + if err != nil { + return fmt.Errorf("error reading tarball: %v", err) + } + + // Determine the path to extract the file to + filePath := filepath.Join(debugDir, header.Name) + + if chartOnly { + err = extractChartYamlFile(tarReader, header, filePath) + } else { + err = extractAllChartData(tarReader, header, filePath) + } + + if err != nil { + return err + } + } + return nil +} + +func extractChartYamlFile(tarReader *tar.Reader, header *tar.Header, filePath string) error { + switch header.Typeflag { + case tar.TypeReg: + if header.Name == "rancher-project-monitoring/Chart.yaml" { + logrus.Info("Found a `Chart.yaml` file to export.") + // Ensure the parent directory exists + parentDir := filepath.Dir(filePath) + if err := os.MkdirAll(parentDir, 0755); err != nil { + return fmt.Errorf("error creating parent directory: %v", err) + } + + // Create regular file + outFile, err := os.Create(filePath) + if err != nil { + return fmt.Errorf("error creating file: %v", err) + } + + // Copy file content + if _, err := io.Copy(outFile, tarReader); err != nil { + outFile.Close() + return fmt.Errorf("error writing file content: %v", err) + } + logrus.Info("The `Chart.yaml` file was exported") + outFile.Close() + } else { + logrus.Debugf("Skipping file: %s\n", header.Name) + } + default: + logrus.Debugf("Skipping file: %s\n", header.Name) + } + return nil +} + +func extractAllChartData(tarReader *tar.Reader, header *tar.Header, filePath string) error { + switch header.Typeflag { + case tar.TypeDir: + // Create directory + if err := os.MkdirAll(filePath, os.FileMode(header.Mode)); err != nil { + return fmt.Errorf("error creating directory: %v", err) + } + case tar.TypeReg: + // Ensure the parent directory exists + parentDir := filepath.Dir(filePath) + if err := os.MkdirAll(parentDir, 0755); err != nil { + return fmt.Errorf("error creating parent directory: %v", err) + } + + // Create regular file + outFile, err := os.Create(filePath) + if err != nil { + return fmt.Errorf("error creating file: %v", err) + } + + // Copy file content + if _, err := io.Copy(outFile, tarReader); err != nil { + outFile.Close() + return fmt.Errorf("error writing file content: %v", err) + } + outFile.Close() + default: + logrus.Debugf("Skipping unsupported file type: %s\n", header.Name) + } + return nil +}