feat(clustertool): add logging verbosity to kubectl apply logics

This commit is contained in:
Kjeld Schouten
2024-10-27 20:09:50 +01:00
parent 21e29da3bb
commit 9adc50b5cd
+54 -12
View File
@@ -11,6 +11,7 @@ import (
"github.com/go-logr/logr" "github.com/go-logr/logr"
"github.com/go-logr/zapr" "github.com/go-logr/zapr"
"github.com/rs/zerolog/log"
"github.com/truecharts/public/clustertool/pkg/helper" "github.com/truecharts/public/clustertool/pkg/helper"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
@@ -26,24 +27,31 @@ import (
// getKubeClient initializes and returns a controller-runtime client.Client // getKubeClient initializes and returns a controller-runtime client.Client
func getKubeClient() (client.Client, error) { func getKubeClient() (client.Client, error) {
log.Trace().Msg("Initializing Kubernetes client")
// Load kubeconfig from the default location // Load kubeconfig from the default location
kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config") kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to load kubeconfig")
return nil, fmt.Errorf("failed to load kubeconfig: %v", err) return nil, fmt.Errorf("failed to load kubeconfig: %v", err)
} }
// Create a controller-runtime client // Create a controller-runtime client
c, err := client.New(config, client.Options{}) c, err := client.New(config, client.Options{})
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to create Kubernetes client")
return nil, fmt.Errorf("failed to create Kubernetes client: %v", err) return nil, fmt.Errorf("failed to create Kubernetes client: %v", err)
} }
log.Debug().Msg("Successfully initialized Kubernetes client")
return c, nil return c, nil
} }
// setupLogger initializes a logger that writes to a buffer and returns both // setupLogger initializes a logger that writes to a buffer and returns both
func setupLogger() (logr.Logger, *bytes.Buffer, error) { func setupLogger() (logr.Logger, *bytes.Buffer, error) {
log.Debug().Msg("Setting up logger")
// Create a buffer to capture logs // Create a buffer to capture logs
var buf bytes.Buffer var buf bytes.Buffer
@@ -65,19 +73,23 @@ func setupLogger() (logr.Logger, *bytes.Buffer, error) {
zapLogger := zap.New(core) zapLogger := zap.New(core)
// Wrap zap logger with zapr to get a logr.Logger interface // Wrap zap logger with zapr to get a logr.Logger interface
log := zapr.NewLogger(zapLogger) logr := zapr.NewLogger(zapLogger)
return log, &buf, nil log.Debug().Msg("Logger setup completed")
return logr, &buf, nil
} }
// applyYAML applies the given YAML data to the Kubernetes cluster using the provided client and logger // applyYAML applies the given YAML data to the Kubernetes cluster using the provided client and logger
func applyYAML(k8sClient client.Client, yamlData []byte, log logr.Logger) error { func applyYAML(k8sClient client.Client, yamlData []byte, logr logr.Logger) error {
log.Trace().Msg("Applying YAML data to the Kubernetes cluster")
// Parse the YAML into KIO nodes // Parse the YAML into KIO nodes
reader := kio.ByteReader{ reader := kio.ByteReader{
Reader: bytes.NewReader(yamlData), Reader: bytes.NewReader(yamlData),
} }
nodes, err := reader.Read() nodes, err := reader.Read()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to parse YAML")
return fmt.Errorf("failed to parse YAML: %v", err) return fmt.Errorf("failed to parse YAML: %v", err)
} }
@@ -85,57 +97,72 @@ func applyYAML(k8sClient client.Client, yamlData []byte, log logr.Logger) error
for _, node := range nodes { for _, node := range nodes {
obj := &unstructured.Unstructured{} obj := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(node.MustString()), obj); err != nil { if err := yaml.Unmarshal([]byte(node.MustString()), obj); err != nil {
log.Error().Err(err).Msg("Failed to unmarshal node")
return fmt.Errorf("failed to unmarshal node: %v", err) return fmt.Errorf("failed to unmarshal node: %v", err)
} }
if err := k8sClient.Patch(context.TODO(), obj, client.Apply, client.FieldOwner("kustomize-controller")); err != nil { if err := k8sClient.Patch(context.TODO(), obj, client.Apply, client.FieldOwner("kustomize-controller")); err != nil {
log.Error().Err(err).Msg("Failed to apply object")
return fmt.Errorf("failed to apply object: %v", err) return fmt.Errorf("failed to apply object: %v", err)
} }
log.Info("Successfully applied object", "object", obj.GetName(), "kind", obj.GetKind(), "namespace", obj.GetNamespace()) log.Info().Msgf("Successfully applied object: %s of kind: %s in namespace: %s", obj.GetName(), obj.GetKind(), obj.GetNamespace())
} }
log.Debug().Msg("YAML application completed")
return nil return nil
} }
// filterLogOutput filters the log data by removing strings that match any of the provided regex patterns // filterLogOutput filters the log data by removing strings that match any of the provided regex patterns
func filterLogOutput(logData string) (string, error) { func filterLogOutput(logData string) (string, error) {
log.Trace().Msg("Filtering log output")
filteredLog := logData filteredLog := logData
for _, pattern := range helper.KubeFilterStr { for _, pattern := range helper.KubeFilterStr {
re, err := regexp.Compile(pattern) re, err := regexp.Compile(pattern)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("Invalid regex pattern '%s'", pattern)
return "", fmt.Errorf("invalid regex pattern '%s': %v", pattern, err) return "", fmt.Errorf("invalid regex pattern '%s': %v", pattern, err)
} }
filteredLog = re.ReplaceAllString(filteredLog, "") filteredLog = re.ReplaceAllString(filteredLog, "")
} }
log.Debug().Msg("Log output filtering completed")
return filteredLog, nil return filteredLog, nil
} }
// KubectlApply applies a YAML file to the Kubernetes cluster and filters the logs // KubectlApply applies a YAML file to the Kubernetes cluster and filters the logs
func KubectlApply(ctx context.Context, filePath string) error { func KubectlApply(ctx context.Context, filePath string) error {
log.Trace().Msgf("Applying YAML file at path: %s", filePath)
// Check if the file exists // Check if the file exists
if _, err := os.Stat(filePath); os.IsNotExist(err) { if _, err := os.Stat(filePath); os.IsNotExist(err) {
log.Error().Err(err).Msgf("File does not exist: %s", filePath)
return fmt.Errorf("file does not exist: %s", filePath) return fmt.Errorf("file does not exist: %s", filePath)
} }
// Read the YAML file // Read the YAML file
yamlData, err := ioutil.ReadFile(filePath) yamlData, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to read YAML file")
return fmt.Errorf("failed to read YAML file: %v", err) return fmt.Errorf("failed to read YAML file: %v", err)
} }
// Initialize logger and buffer // Initialize logger and buffer
log, buf, err := setupLogger() logr, buf, err := setupLogger()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to set up logger")
return fmt.Errorf("failed to set up logger: %v", err) return fmt.Errorf("failed to set up logger: %v", err)
} }
// Initialize Kubernetes client // Initialize Kubernetes client
k8sClient, err := getKubeClient() k8sClient, err := getKubeClient()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to initialize Kubernetes client")
return err return err
} }
// Apply the YAML to the cluster // Apply the YAML to the cluster
if err := applyYAML(k8sClient, yamlData, log); err != nil { if err := applyYAML(k8sClient, yamlData, logr); err != nil {
log.Error().Err(err).Msg("Failed to apply YAML")
return fmt.Errorf("failed to apply YAML: %v", err) return fmt.Errorf("failed to apply YAML: %v", err)
} }
@@ -145,25 +172,31 @@ func KubectlApply(ctx context.Context, filePath string) error {
// Filter the logs // Filter the logs
filteredLog, err := filterLogOutput(logOutput) filteredLog, err := filterLogOutput(logOutput)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to filter logs")
return fmt.Errorf("failed to filter logs: %v", err) return fmt.Errorf("failed to filter logs: %v", err)
} }
// Output filtered logs // Output filtered logs
fmt.Println(filteredLog) fmt.Println(filteredLog)
log.Info().Msg("KubectlApply operation completed")
return nil return nil
} }
// KubectlApplyKustomize applies a kustomize directory or file to the Kubernetes cluster and filters the logs // KubectlApplyKustomize applies a kustomize directory or file to the Kubernetes cluster and filters the logs
func KubectlApplyKustomize(ctx context.Context, filePath string) error { func KubectlApplyKustomize(ctx context.Context, filePath string) error {
log.Trace().Msgf("Applying Kustomize directory or file at path: %s", filePath)
// Check if the path exists // Check if the path exists
if _, err := os.Stat(filePath); os.IsNotExist(err) { if _, err := os.Stat(filePath); os.IsNotExist(err) {
log.Error().Err(err).Msgf("Path does not exist: %s", filePath)
return fmt.Errorf("path does not exist: %s", filePath) return fmt.Errorf("path does not exist: %s", filePath)
} }
// Determine if the path is a directory or a file // Determine if the path is a directory or a file
fileInfo, err := os.Stat(filePath) fileInfo, err := os.Stat(filePath)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to stat path")
return fmt.Errorf("failed to stat path: %v", err) return fmt.Errorf("failed to stat path: %v", err)
} }
@@ -171,9 +204,11 @@ func KubectlApplyKustomize(ctx context.Context, filePath string) error {
if fileInfo.IsDir() { if fileInfo.IsDir() {
// If it's a directory, use it as the kustomize path // If it's a directory, use it as the kustomize path
kustomizePath = filePath kustomizePath = filePath
log.Debug().Msgf("Using directory as kustomize path: %s", kustomizePath)
} else { } else {
// If it's a file, use its directory as the kustomize path // If it's a file, use its directory as the kustomize path
kustomizePath = filepath.Dir(filePath) kustomizePath = filepath.Dir(filePath)
log.Debug().Msgf("Using file's directory as kustomize path: %s", kustomizePath)
} }
// Process kustomize to get the YAML output // Process kustomize to get the YAML output
@@ -181,30 +216,35 @@ func KubectlApplyKustomize(ctx context.Context, filePath string) error {
k := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) k := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
resMap, err := k.Run(fSys, kustomizePath) resMap, err := k.Run(fSys, kustomizePath)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to run kustomize")
return fmt.Errorf("failed to run kustomize: %v", err) return fmt.Errorf("failed to run kustomize: %v", err)
} }
// Convert ResMap to YAML // Get the YAML output from the resMap
output, err := resMap.AsYaml() yamlData, err := resMap.AsYaml()
if err != nil { if err != nil {
return fmt.Errorf("failed to convert ResMap to YAML: %v", err) log.Error().Err(err).Msg("Failed to convert kustomize output to YAML")
return fmt.Errorf("failed to convert kustomize output to YAML: %v", err)
} }
// Initialize logger and buffer // Initialize logger and buffer
log, buf, err := setupLogger() logr, buf, err := setupLogger()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to set up logger")
return fmt.Errorf("failed to set up logger: %v", err) return fmt.Errorf("failed to set up logger: %v", err)
} }
// Initialize Kubernetes client // Initialize Kubernetes client
k8sClient, err := getKubeClient() k8sClient, err := getKubeClient()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to initialize Kubernetes client")
return err return err
} }
// Apply the YAML to the cluster // Apply the YAML to the cluster
if err := applyYAML(k8sClient, output, log); err != nil { if err := applyYAML(k8sClient, yamlData, logr); err != nil {
return fmt.Errorf("failed to apply YAML: %v", err) log.Error().Err(err).Msg("Failed to apply YAML from kustomize")
return fmt.Errorf("failed to apply YAML from kustomize: %v", err)
} }
// Get log output from buffer // Get log output from buffer
@@ -213,11 +253,13 @@ func KubectlApplyKustomize(ctx context.Context, filePath string) error {
// Filter the logs // Filter the logs
filteredLog, err := filterLogOutput(logOutput) filteredLog, err := filterLogOutput(logOutput)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to filter logs")
return fmt.Errorf("failed to filter logs: %v", err) return fmt.Errorf("failed to filter logs: %v", err)
} }
// Output filtered logs // Output filtered logs
fmt.Println(filteredLog) fmt.Println(filteredLog)
log.Info().Msg("KubectlApplyKustomize operation completed")
return nil return nil
} }