Skip to content

Commit

Permalink
feat(clustertool): add logging verbosity to kubectl apply logics
Browse files Browse the repository at this point in the history
PrivatePuffin committed Oct 27, 2024

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
1 parent 21e29da commit 9adc50b
Showing 1 changed file with 54 additions and 12 deletions.
66 changes: 54 additions & 12 deletions clustertool/pkg/kubectlcmds/apply.go
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import (

"github.com/go-logr/logr"
"github.com/go-logr/zapr"
"github.com/rs/zerolog/log"
"github.com/truecharts/public/clustertool/pkg/helper"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
@@ -26,24 +27,31 @@ import (

// getKubeClient initializes and returns a controller-runtime client.Client
func getKubeClient() (client.Client, error) {
log.Trace().Msg("Initializing Kubernetes client")

// Load kubeconfig from the default location
kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
log.Error().Err(err).Msg("Failed to load kubeconfig")
return nil, fmt.Errorf("failed to load kubeconfig: %v", err)
}

// Create a controller-runtime client
c, err := client.New(config, client.Options{})
if err != nil {
log.Error().Err(err).Msg("Failed to create Kubernetes client")
return nil, fmt.Errorf("failed to create Kubernetes client: %v", err)
}

log.Debug().Msg("Successfully initialized Kubernetes client")
return c, nil
}

// setupLogger initializes a logger that writes to a buffer and returns both
func setupLogger() (logr.Logger, *bytes.Buffer, error) {
log.Debug().Msg("Setting up logger")

// Create a buffer to capture logs
var buf bytes.Buffer

@@ -65,77 +73,96 @@ func setupLogger() (logr.Logger, *bytes.Buffer, error) {
zapLogger := zap.New(core)

// 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
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
reader := kio.ByteReader{
Reader: bytes.NewReader(yamlData),
}
nodes, err := reader.Read()
if err != nil {
log.Error().Err(err).Msg("Failed to parse YAML")
return fmt.Errorf("failed to parse YAML: %v", err)
}

// Apply each node to the cluster
for _, node := range nodes {
obj := &unstructured.Unstructured{}
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)
}
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)
}
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
}

// filterLogOutput filters the log data by removing strings that match any of the provided regex patterns
func filterLogOutput(logData string) (string, error) {
log.Trace().Msg("Filtering log output")

filteredLog := logData
for _, pattern := range helper.KubeFilterStr {
re, err := regexp.Compile(pattern)
if err != nil {
log.Error().Err(err).Msgf("Invalid regex pattern '%s'", pattern)
return "", fmt.Errorf("invalid regex pattern '%s': %v", pattern, err)
}
filteredLog = re.ReplaceAllString(filteredLog, "")
}

log.Debug().Msg("Log output filtering completed")
return filteredLog, nil
}

// KubectlApply applies a YAML file to the Kubernetes cluster and filters the logs
func KubectlApply(ctx context.Context, filePath string) error {
log.Trace().Msgf("Applying YAML file at path: %s", filePath)

// Check if the file exists
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)
}

// Read the YAML file
yamlData, err := ioutil.ReadFile(filePath)
if err != nil {
log.Error().Err(err).Msg("Failed to read YAML file")
return fmt.Errorf("failed to read YAML file: %v", err)
}

// Initialize logger and buffer
log, buf, err := setupLogger()
logr, buf, err := setupLogger()
if err != nil {
log.Error().Err(err).Msg("Failed to set up logger")
return fmt.Errorf("failed to set up logger: %v", err)
}

// Initialize Kubernetes client
k8sClient, err := getKubeClient()
if err != nil {
log.Error().Err(err).Msg("Failed to initialize Kubernetes client")
return err
}

// 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)
}

@@ -145,66 +172,79 @@ func KubectlApply(ctx context.Context, filePath string) error {
// Filter the logs
filteredLog, err := filterLogOutput(logOutput)
if err != nil {
log.Error().Err(err).Msg("Failed to filter logs")
return fmt.Errorf("failed to filter logs: %v", err)
}

// Output filtered logs
fmt.Println(filteredLog)
log.Info().Msg("KubectlApply operation completed")

return nil
}

// KubectlApplyKustomize applies a kustomize directory or file to the Kubernetes cluster and filters the logs
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
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)
}

// Determine if the path is a directory or a file
fileInfo, err := os.Stat(filePath)
if err != nil {
log.Error().Err(err).Msg("Failed to stat path")
return fmt.Errorf("failed to stat path: %v", err)
}

var kustomizePath string
if fileInfo.IsDir() {
// If it's a directory, use it as the kustomize path
kustomizePath = filePath
log.Debug().Msgf("Using directory as kustomize path: %s", kustomizePath)
} else {
// If it's a file, use its directory as the kustomize path
kustomizePath = filepath.Dir(filePath)
log.Debug().Msgf("Using file's directory as kustomize path: %s", kustomizePath)
}

// Process kustomize to get the YAML output
fSys := filesys.MakeFsOnDisk()
k := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
resMap, err := k.Run(fSys, kustomizePath)
if err != nil {
log.Error().Err(err).Msg("Failed to run kustomize")
return fmt.Errorf("failed to run kustomize: %v", err)
}

// Convert ResMap to YAML
output, err := resMap.AsYaml()
// Get the YAML output from the resMap
yamlData, err := resMap.AsYaml()
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
log, buf, err := setupLogger()
logr, buf, err := setupLogger()
if err != nil {
log.Error().Err(err).Msg("Failed to set up logger")
return fmt.Errorf("failed to set up logger: %v", err)
}

// Initialize Kubernetes client
k8sClient, err := getKubeClient()
if err != nil {
log.Error().Err(err).Msg("Failed to initialize Kubernetes client")
return err
}

// Apply the YAML to the cluster
if err := applyYAML(k8sClient, output, log); err != nil {
return fmt.Errorf("failed to apply YAML: %v", err)
if err := applyYAML(k8sClient, yamlData, logr); err != nil {
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
@@ -213,11 +253,13 @@ func KubectlApplyKustomize(ctx context.Context, filePath string) error {
// Filter the logs
filteredLog, err := filterLogOutput(logOutput)
if err != nil {
log.Error().Err(err).Msg("Failed to filter logs")
return fmt.Errorf("failed to filter logs: %v", err)
}

// Output filtered logs
fmt.Println(filteredLog)
log.Info().Msg("KubectlApplyKustomize operation completed")

return nil
}

0 comments on commit 9adc50b

Please sign in to comment.