From eb474f74a355c67f99e84772c1c117fce624f8ad Mon Sep 17 00:00:00 2001 From: Dan Pock Date: Mon, 16 Dec 2024 18:29:38 -0500 Subject: [PATCH 1/5] Add chart Debug method --- .gitignore | 3 +- cmd/prometheus-federator/main.go | 2 + pkg/debug/chart.go | 106 +++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 pkg/debug/chart.go diff --git a/.gitignore b/.gitignore index 0d4b31bd..8c7ea87f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ dev/ kubeconfig*.yaml get_helm.sh Dockerfile.dapper* -!Dockerfile.dapper \ No newline at end of file +!Dockerfile.dapper +/.debug \ No newline at end of file diff --git a/cmd/prometheus-federator/main.go b/cmd/prometheus-federator/main.go index 25ff2550..9941b45a 100644 --- a/cmd/prometheus-federator/main.go +++ b/cmd/prometheus-federator/main.go @@ -9,6 +9,7 @@ import ( _ "net/http/pprof" "os" + "github.com/rancher/prometheus-federator/pkg/debug" "github.com/rancher/prometheus-federator/pkg/helm-project-operator/controllers/common" "github.com/rancher/prometheus-federator/pkg/helm-project-operator/operator" "github.com/rancher/prometheus-federator/pkg/version" @@ -84,5 +85,6 @@ func main() { Version: version.FriendlyVersion(), }) cmd = command.AddDebug(cmd, &debugConfig) + cmd.AddCommand(debug.ChartDebugSubCommand(base64TgzChart)) command.Main(cmd) } diff --git a/pkg/debug/chart.go b/pkg/debug/chart.go new file mode 100644 index 00000000..d6a0dfc3 --- /dev/null +++ b/pkg/debug/chart.go @@ -0,0 +1,106 @@ +package debug + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "encoding/base64" + "fmt" + "github.com/spf13/cobra" + "io" + "os" + "path/filepath" +) + +func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { + return &cobra.Command{ + Use: "debug-chart", + Short: "This command helps debug the internal chart files", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("TODO debug") + // TODO: use straing data from base64ChartTarball to: + // Un-base64 the data to get a raw tgz file, + // Prompt for user input - in the future, for now just use local CWD, + // Save the files of the charts tar extracted to the local CWD + chartTarballData, err := base64.StdEncoding.DecodeString(base64ChartTarball) + if err != nil { + fmt.Println("error:", err) + return + } + + 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 + } + 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 + } + + // 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) + + 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) + } + } + + fmt.Println("Chart files successfully extracted to", debugDir) + }, + } +} From b1fd904d95c2b76f7f3411ef56fcff22017cd0ac Mon Sep 17 00:00:00 2001 From: Dan Pock Date: Tue, 17 Dec 2024 09:39:46 -0500 Subject: [PATCH 2/5] lint --- pkg/debug/chart.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/debug/chart.go b/pkg/debug/chart.go index d6a0dfc3..ed7f991e 100644 --- a/pkg/debug/chart.go +++ b/pkg/debug/chart.go @@ -6,17 +6,18 @@ import ( "compress/gzip" "encoding/base64" "fmt" - "github.com/spf13/cobra" "io" "os" "path/filepath" + + "github.com/spf13/cobra" ) func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { return &cobra.Command{ Use: "debug-chart", Short: "This command helps debug the internal chart files", - Run: func(cmd *cobra.Command, args []string) { + Run: func(_ *cobra.Command, _ []string) { fmt.Println("TODO debug") // TODO: use straing data from base64ChartTarball to: // Un-base64 the data to get a raw tgz file, From a864192fdace6ae50058d039a158f52ab997e9d1 Mon Sep 17 00:00:00 2001 From: Dan Pock Date: Wed, 18 Dec 2024 13:00:28 -0500 Subject: [PATCH 3/5] Add flag to only dump Chart.yaml from embedded --- pkg/debug/chart.go | 57 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/pkg/debug/chart.go b/pkg/debug/chart.go index ed7f991e..c7ef318a 100644 --- a/pkg/debug/chart.go +++ b/pkg/debug/chart.go @@ -10,19 +10,23 @@ import ( "os" "path/filepath" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { - return &cobra.Command{ + chartDebug := &cobra.Command{ Use: "debug-chart", Short: "This command helps debug the internal chart files", - Run: func(_ *cobra.Command, _ []string) { - fmt.Println("TODO debug") - // TODO: use straing data from base64ChartTarball to: - // Un-base64 the data to get a raw tgz file, - // Prompt for user input - in the future, for now just use local CWD, - // Save the files of the charts tar extracted to the local CWD + Run: func(cmd *cobra.Command, _ []string) { + chartOnly, _ := cmd.Flags().GetBool("chart-only") + 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) if err != nil { fmt.Println("error:", err) @@ -67,6 +71,43 @@ func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { // 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 @@ -104,4 +145,6 @@ func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { fmt.Println("Chart files successfully extracted to", debugDir) }, } + chartDebug.PersistentFlags().BoolP("chart-only", "C", false, "When set, only the `Chart.yaml` will be exported.") + return chartDebug } From d849393a413d1c9bf6ed714c0db78ef68cd2bffc Mon Sep 17 00:00:00 2001 From: Dan Pock Date: Thu, 19 Dec 2024 12:41:37 -0500 Subject: [PATCH 4/5] refactor debug command --- pkg/debug/chart.go | 230 ++++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 105 deletions(-) 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 +} From d49d2170dc5777a6d7ca5b30fe7c15482c152bb9 Mon Sep 17 00:00:00 2001 From: Dan Pock Date: Fri, 20 Dec 2024 10:00:19 -0500 Subject: [PATCH 5/5] adjust var scope --- pkg/debug/chart.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/debug/chart.go b/pkg/debug/chart.go index 803ec0d1..cbb67fec 100644 --- a/pkg/debug/chart.go +++ b/pkg/debug/chart.go @@ -15,11 +15,8 @@ import ( "github.com/spf13/cobra" ) -var ( - chartOnly bool -) - func ChartDebugSubCommand(base64ChartTarball string) *cobra.Command { + var chartOnly bool chartDebug := &cobra.Command{ Use: "debug-chart", Short: "This command helps debug the internal chart files",