From 956fd58b23edf4e001eecc700878b16973f66fbe Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 19 May 2026 13:32:21 +0530 Subject: [PATCH 01/64] add request id to logs --- pkg/driver/controllerserver.go | 61 +++++++++------ pkg/driver/interceptor.go | 56 ++++++++++++++ pkg/driver/server.go | 5 +- pkg/logger/logger.go | 63 ++++++++++++++++ pkg/requestid/requestid.go | 78 +++++++++++++++++++ pkg/requestid/requestid_test.go | 128 ++++++++++++++++++++++++++++++++ 6 files changed, 369 insertions(+), 22 deletions(-) create mode 100644 pkg/driver/interceptor.go create mode 100644 pkg/logger/logger.go create mode 100644 pkg/requestid/requestid.go create mode 100644 pkg/requestid/requestid_test.go diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index a2ee8de8..885ecb73 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -22,6 +22,8 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/IBM/ibm-object-csi-driver/pkg/s3client" "github.com/IBM/ibm-object-csi-driver/pkg/utils" "github.com/aws/smithy-go" @@ -42,7 +44,11 @@ type controllerServer struct { Logger *zap.Logger } -func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { +func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { + // Extract request ID from context (added by interceptor) + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + var ( bucketName string endPoint string @@ -54,30 +60,37 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum quotaLimitEnabled bool ) + log.Info("CreateVolume started", zap.String("volume_name", req.GetName())) + modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in modifying requests %v", err)) + logger.Error(ctx, cs.Logger, "Error modifying request", zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) } - klog.V(3).Infof("CSIControllerServer-CreateVolume: Request: %v", modifiedRequest.(*csi.CreateVolumeRequest)) + log.Debug("CreateVolume request details", zap.Any("request", modifiedRequest.(*csi.CreateVolumeRequest))) volumeName, err := sanitizeVolumeID(req.GetName()) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in sanitizeVolumeID %v", err)) + logger.Error(ctx, cs.Logger, "Error sanitizing volume ID", zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in sanitizeVolumeID %v", reqID, err)) } volumeID := volumeName if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume name missing in request") + logger.Error(ctx, cs.Logger, "Volume name missing in request") + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume name missing in request", reqID)) } - klog.Infof("Got a request to create volume: %s", volumeID) + log.Info("Processing volume creation", zap.String("volume_id", volumeID)) caps := req.GetVolumeCapabilities() if caps == nil { - return nil, status.Error(codes.InvalidArgument, "Volume Capabilities missing in request") + logger.Error(ctx, cs.Logger, "Volume capabilities missing in request") + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume Capabilities missing in request", reqID)) } for _, cap := range caps { - klog.Infof("Volume capability: %s", cap) + log.Debug("Volume capability", zap.String("capability", cap.String())) if cap.GetBlock() != nil { - return nil, status.Error(codes.InvalidArgument, "Volume type block Volume not supported") + logger.Error(ctx, cs.Logger, "Block volume not supported") + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume type block Volume not supported", reqID)) } } @@ -85,32 +98,35 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum if params == nil { params = make(map[string]string) } - klog.Info("CreateVolume Parameters:\n\t", params) + log.Info("CreateVolume parameters received", zap.Int("param_count", len(params))) secretMap := req.GetSecrets() - klog.Info("req.GetSecrets() length:\t", len(secretMap)) + log.Info("Secrets received", zap.Int("secret_count", len(secretMap))) var customSecretName string if len(secretMap) == 0 { - klog.Info("Did not find the secret that matches pvc name. Fetching custom secret from PVC annotations") + log.Info("No secret in request, fetching custom secret from PVC annotations") pvcName = params[constants.PVCNameKey] pvcNamespace = params[constants.PVCNamespaceKey] if pvcName == "" { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("pvcName not specified, could not fetch the secret %v", err)) + logger.Error(ctx, cs.Logger, "PVC name not specified") + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] pvcName not specified, could not fetch the secret", reqID)) } if pvcNamespace == "" { pvcNamespace = constants.DefaultNamespace } + log.Info("Fetching PVC", zap.String("pvc_name", pvcName), zap.String("namespace", pvcNamespace)) pvcRes, err := cs.Stats.GetPVC(pvcName, pvcNamespace) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("PVC resource not found %v", err)) + logger.Error(ctx, cs.Logger, "PVC resource not found", zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] PVC resource not found %v", reqID, err)) } - klog.Info("pvc annotations:\n\t", pvcRes.Annotations) + log.Debug("PVC annotations", zap.Any("annotations", pvcRes.Annotations)) pvcAnnotations := pvcRes.Annotations @@ -118,27 +134,30 @@ func (cs *controllerServer) CreateVolume(_ context.Context, req *csi.CreateVolum secretNamespace := pvcAnnotations[constants.SecretNamespaceKey] if customSecretName == "" { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations, could not fetch the secret %v", err)) + logger.Error(ctx, cs.Logger, "Secret name annotation not found in PVC") + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations", reqID)) } if secretNamespace == "" { - klog.Info("secretNamespace annotation 'cos.csi.driver/secret-namespace' not specified in PVC annotations:\t", pvcRes.Annotations, "\t trying to fetch the secret in default namespace") + log.Warn("Secret namespace not specified in PVC annotations, using default namespace") secretNamespace = constants.DefaultNamespace } + log.Info("Fetching secret", zap.String("secret_name", customSecretName), zap.String("namespace", secretNamespace)) secret, err := cs.Stats.GetSecret(customSecretName, secretNamespace) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Secret resource not found %v", err)) + logger.Error(ctx, cs.Logger, "Secret resource not found", zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) } secretMapCustom := parseCustomSecret(secret) - klog.Info("custom secret parameters parsed successfully, length of custom secret: ", len(secretMapCustom)) + log.Info("Custom secret parsed successfully", zap.Int("secret_param_count", len(secretMapCustom))) if objectPath, exists := secretMapCustom["objectPath"]; exists { - klog.Infof("volume_id:%q objectPath found in secret: %q", volumeID, objectPath) + log.Info("ObjectPath found in secret", zap.String("volume_id", volumeID), zap.String("object_path", objectPath)) params["objectPath"] = objectPath } else { - klog.Infof("volume_id:%q no objectPath in secret (mounting bucket root)", volumeID) + log.Info("No objectPath in secret, mounting bucket root", zap.String("volume_id", volumeID)) } secretMap = secretMapCustom diff --git a/pkg/driver/interceptor.go b/pkg/driver/interceptor.go new file mode 100644 index 00000000..609cd803 --- /dev/null +++ b/pkg/driver/interceptor.go @@ -0,0 +1,56 @@ +/******************************************************************************* + * IBM Confidential + * OCO Source Materials + * IBM Cloud Kubernetes Service, 5737-D43 + * (C) Copyright IBM Corp. 2023 All Rights Reserved. + * The source code for this program is not published or otherwise divested of + * its trade secrets, irrespective of what has been deposited with + * the U.S. Copyright Office. + ******************************************************************************/ + +package driver + +import ( + "context" + "time" + + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "go.uber.org/zap" + "google.golang.org/grpc" +) + +// UnaryServerInterceptor adds request ID to all unary RPC calls and logs request lifecycle +func UnaryServerInterceptor(logger *zap.Logger) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + // Generate or extract request ID + ctx, reqID := requestid.GetOrGenerate(ctx) + + // Log request start + startTime := time.Now() + logger.Info("gRPC request started", + zap.String("request_id", reqID), + zap.String("method", info.FullMethod), + zap.Time("start_time", startTime)) + + // Call the handler + resp, err := handler(ctx, req) + + // Log request completion + duration := time.Since(startTime) + if err != nil { + logger.Error("gRPC request failed", + zap.String("request_id", reqID), + zap.String("method", info.FullMethod), + zap.Duration("duration", duration), + zap.Error(err)) + } else { + logger.Info("gRPC request completed", + zap.String("request_id", reqID), + zap.String("method", info.FullMethod), + zap.Duration("duration", duration)) + } + + return resp, err + } +} + diff --git a/pkg/driver/server.go b/pkg/driver/server.go index 30c3cc94..f2081112 100644 --- a/pkg/driver/server.go +++ b/pkg/driver/server.go @@ -77,7 +77,10 @@ func (s *nonBlockingGRPCServer) Setup(endpoint string, ids csi.IdentityServer, c s.logger.Info("nonBlockingGRPCServer-Setup", zap.Reflect("Endpoint", endpoint)) opts := []grpc.ServerOption{ - grpc.UnaryInterceptor(logGRPC), + grpc.ChainUnaryInterceptor( + UnaryServerInterceptor(s.logger), // Request ID interceptor + logGRPC, // Legacy logging interceptor + ), } u, err := url.Parse(endpoint) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 00000000..477d17b4 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,63 @@ +/******************************************************************************* + * IBM Confidential + * OCO Source Materials + * IBM Cloud Kubernetes Service, 5737-D43 + * (C) Copyright IBM Corp. 2023 All Rights Reserved. + * The source code for this program is not published or otherwise divested of + * its trade secrets, irrespective of what has been deposited with + * the U.S. Copyright Office. + ******************************************************************************/ + +// Package logger provides utilities for structured logging with request ID tracking +package logger + +import ( + "context" + + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "go.uber.org/zap" +) + +// WithRequestID returns a logger with request ID field added +// If no request ID exists in context, returns the original logger +func WithRequestID(ctx context.Context, logger *zap.Logger) *zap.Logger { + if logger == nil { + return nil + } + if reqID := requestid.FromContext(ctx); reqID != "" { + return logger.With(zap.String("request_id", reqID)) + } + return logger +} + +// Info logs an info message with request ID from context +func Info(ctx context.Context, logger *zap.Logger, msg string, fields ...zap.Field) { + WithRequestID(ctx, logger).Info(msg, fields...) +} + +// Error logs an error message with request ID from context +func Error(ctx context.Context, logger *zap.Logger, msg string, fields ...zap.Field) { + WithRequestID(ctx, logger).Error(msg, fields...) +} + +// Warn logs a warning message with request ID from context +func Warn(ctx context.Context, logger *zap.Logger, msg string, fields ...zap.Field) { + WithRequestID(ctx, logger).Warn(msg, fields...) +} + +// Debug logs a debug message with request ID from context +func Debug(ctx context.Context, logger *zap.Logger, msg string, fields ...zap.Field) { + WithRequestID(ctx, logger).Debug(msg, fields...) +} + +// Fatal logs a fatal message with request ID from context and exits +func Fatal(ctx context.Context, logger *zap.Logger, msg string, fields ...zap.Field) { + WithRequestID(ctx, logger).Fatal(msg, fields...) +} + +// Panic logs a panic message with request ID from context and panics +func Panic(ctx context.Context, logger *zap.Logger, msg string, fields ...zap.Field) { + WithRequestID(ctx, logger).Panic(msg, fields...) +} + + diff --git a/pkg/requestid/requestid.go b/pkg/requestid/requestid.go new file mode 100644 index 00000000..3a766829 --- /dev/null +++ b/pkg/requestid/requestid.go @@ -0,0 +1,78 @@ +/******************************************************************************* + * IBM Confidential + * OCO Source Materials + * IBM Cloud Kubernetes Service, 5737-D43 + * (C) Copyright IBM Corp. 2023 All Rights Reserved. + * The source code for this program is not published or otherwise divested of + * its trade secrets, irrespective of what has been deposited with + * the U.S. Copyright Office. + ******************************************************************************/ + +// Package requestid provides utilities for generating and managing request IDs +// throughout the CSI driver lifecycle for better debugging and log correlation. +package requestid + +import ( + "context" + + "github.com/google/uuid" +) + +type contextKey string + +const ( + // RequestIDKey is the context key for storing request IDs + RequestIDKey contextKey = "request-id" +) + +// Generate creates a new UUID v4 request ID +func Generate() string { + return uuid.New().String() +} + +// WithRequestID adds a request ID to the context +func WithRequestID(ctx context.Context, requestID string) context.Context { + if requestID == "" { + requestID = Generate() + } + return context.WithValue(ctx, RequestIDKey, requestID) +} + +// FromContext extracts the request ID from context +// Returns empty string if no request ID is found +func FromContext(ctx context.Context) string { + if ctx == nil { + return "" + } + if requestID, ok := ctx.Value(RequestIDKey).(string); ok { + return requestID + } + return "" +} + +// GetOrGenerate gets the request ID from context or generates a new one +// Returns the updated context and the request ID +func GetOrGenerate(ctx context.Context) (context.Context, string) { + if ctx == nil { + ctx = context.Background() + } + + requestID := FromContext(ctx) + if requestID == "" { + requestID = Generate() + ctx = WithRequestID(ctx, requestID) + } + return ctx, requestID +} + +// MustGet extracts request ID from context, panics if not found +// This should only be used in scenarios where request ID is guaranteed to exist +func MustGet(ctx context.Context) string { + requestID := FromContext(ctx) + if requestID == "" { + panic("request ID not found in context") + } + return requestID +} + + diff --git a/pkg/requestid/requestid_test.go b/pkg/requestid/requestid_test.go new file mode 100644 index 00000000..fa1af8f4 --- /dev/null +++ b/pkg/requestid/requestid_test.go @@ -0,0 +1,128 @@ +/******************************************************************************* + * IBM Confidential + * OCO Source Materials + * IBM Cloud Kubernetes Service, 5737-D43 + * (C) Copyright IBM Corp. 2023 All Rights Reserved. + * The source code for this program is not published or otherwise divested of + * its trade secrets, irrespective of what has been deposited with + * the U.S. Copyright Office. + ******************************************************************************/ + +package requestid + +import ( + "context" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +func TestGenerate(t *testing.T) { + requestID := Generate() + assert.NotEmpty(t, requestID) + + // Verify it's a valid UUID + _, err := uuid.Parse(requestID) + assert.NoError(t, err) + + // Verify uniqueness + requestID2 := Generate() + assert.NotEqual(t, requestID, requestID2) +} + +func TestWithRequestID(t *testing.T) { + ctx := context.Background() + testID := "test-request-id-123" + + ctx = WithRequestID(ctx, testID) + retrievedID := FromContext(ctx) + + assert.Equal(t, testID, retrievedID) +} + +func TestWithRequestIDEmpty(t *testing.T) { + ctx := context.Background() + + // Empty string should generate a new ID + ctx = WithRequestID(ctx, "") + retrievedID := FromContext(ctx) + + assert.NotEmpty(t, retrievedID) + _, err := uuid.Parse(retrievedID) + assert.NoError(t, err) +} + +func TestFromContext(t *testing.T) { + t.Run("with request ID", func(t *testing.T) { + ctx := context.Background() + testID := "test-id-456" + ctx = WithRequestID(ctx, testID) + + retrievedID := FromContext(ctx) + assert.Equal(t, testID, retrievedID) + }) + + t.Run("without request ID", func(t *testing.T) { + ctx := context.Background() + retrievedID := FromContext(ctx) + assert.Empty(t, retrievedID) + }) + + t.Run("nil context", func(t *testing.T) { + retrievedID := FromContext(nil) + assert.Empty(t, retrievedID) + }) +} + +func TestGetOrGenerate(t *testing.T) { + t.Run("existing request ID", func(t *testing.T) { + ctx := context.Background() + existingID := "existing-id-789" + ctx = WithRequestID(ctx, existingID) + + newCtx, requestID := GetOrGenerate(ctx) + assert.Equal(t, existingID, requestID) + assert.Equal(t, existingID, FromContext(newCtx)) + }) + + t.Run("no existing request ID", func(t *testing.T) { + ctx := context.Background() + + newCtx, requestID := GetOrGenerate(ctx) + assert.NotEmpty(t, requestID) + assert.Equal(t, requestID, FromContext(newCtx)) + + // Verify it's a valid UUID + _, err := uuid.Parse(requestID) + assert.NoError(t, err) + }) + + t.Run("nil context", func(t *testing.T) { + newCtx, requestID := GetOrGenerate(nil) + assert.NotNil(t, newCtx) + assert.NotEmpty(t, requestID) + assert.Equal(t, requestID, FromContext(newCtx)) + }) +} + +func TestMustGet(t *testing.T) { + t.Run("with request ID", func(t *testing.T) { + ctx := context.Background() + testID := "must-get-test-id" + ctx = WithRequestID(ctx, testID) + + retrievedID := MustGet(ctx) + assert.Equal(t, testID, retrievedID) + }) + + t.Run("without request ID panics", func(t *testing.T) { + ctx := context.Background() + + assert.Panics(t, func() { + MustGet(ctx) + }) + }) +} + + From 5df27229a61be7fce5765d890c1dbbd791aaf847 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 19 May 2026 14:29:31 +0530 Subject: [PATCH 02/64] req id implementation in controller --- pkg/driver/controllerserver.go | 129 +++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 45 deletions(-) diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index 885ecb73..68bfb9b3 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -163,25 +163,28 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol secretMap = secretMapCustom } if quotaLimitStr, ok := secretMap[constants.QuotaLimitKey]; ok && quotaLimitStr != "" { - klog.Infof("quotaLimit from secretMap: %q", quotaLimitStr) + log.Info(fmt.Sprintf("[%s] Quota limit parameter found", reqID), zap.String("quota_limit", quotaLimitStr)) quotaLimitEnabled, err = strconv.ParseBool(quotaLimitStr) if err != nil { + log.Error(fmt.Sprintf("[%s] Invalid quota limit value", reqID), zap.String("value", quotaLimitStr), zap.Error(err)) return nil, status.Error(codes.InvalidArgument, - fmt.Sprintf("invalid quotaLimit value %q: must be 'true' or 'false'", quotaLimitStr)) + fmt.Sprintf("[%s] invalid quotaLimit value %q: must be 'true' or 'false'", reqID, quotaLimitStr)) } if quotaLimitEnabled { if secretMap[constants.ResourceConfigApiKey] == "" { + log.Error(fmt.Sprintf("[%s] Resource config API key missing for quota limit", reqID)) return nil, status.Error(codes.InvalidArgument, - "resourceConfigApiKey missing in secret, cannot set quota limit for bucket") + fmt.Sprintf("[%s] resourceConfigApiKey missing in secret, cannot set quota limit for bucket", reqID)) } quotaBytes := req.GetCapacityRange().GetRequiredBytes() if quotaBytes <= 0 { + log.Error(fmt.Sprintf("[%s] Invalid storage size for quota limit", reqID), zap.Int64("bytes", quotaBytes)) return nil, status.Error(codes.InvalidArgument, - "enable quotaLimit requested but no positive storage size requested in PVC") + fmt.Sprintf("[%s] enable quotaLimit requested but no positive storage size requested in PVC", reqID)) } - klog.Infof("enable quota limit requested with %d bytes", quotaBytes) + log.Info(fmt.Sprintf("[%s] Quota limit enabled", reqID), zap.Int64("quota_bytes", quotaBytes)) } } @@ -192,7 +195,8 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol params["cosEndpoint"] = endPoint } if endPoint == "" { - return nil, status.Error(codes.InvalidArgument, "cosEndpoint unknown") + log.Error(fmt.Sprintf("[%s] COS endpoint not specified", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] cosEndpoint unknown", reqID)) } locationConstraint = secretMap["locationConstraint"] @@ -202,12 +206,13 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol params["locationConstraint"] = locationConstraint } if locationConstraint == "" { - return nil, status.Error(codes.InvalidArgument, "locationConstraint unknown") + log.Error(fmt.Sprintf("[%s] Location constraint not specified", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] locationConstraint unknown", reqID)) } kpRootKeyCrn = secretMap["kpRootKeyCRN"] if kpRootKeyCrn != "" { - klog.Infof("key protect root key crn provided for bucket creation") + log.Info(fmt.Sprintf("[%s] Key Protect root key CRN provided for bucket encryption", reqID)) } mounter := secretMap["mounter"] @@ -216,6 +221,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } else { params["mounter"] = mounter } + log.Info(fmt.Sprintf("[%s] Mounter type configured", reqID), zap.String("mounter", mounter)) bucketName = secretMap["bucketName"] @@ -223,128 +229,161 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if val, ok := secretMap[constants.BucketVersioning]; ok && val != "" { enable := strings.ToLower(strings.TrimSpace(val)) if enable != "true" && enable != "false" { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Invalid BucketVersioning value in secret: %s. Value set %s. Must be 'true' or 'false'", customSecretName, val)) + log.Error(fmt.Sprintf("[%s] Invalid bucket versioning value in secret", reqID), zap.String("value", val)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Invalid BucketVersioning value in secret: %s. Value set %s. Must be 'true' or 'false'", reqID, customSecretName, val)) } bucketVersioning = enable - klog.Infof("BucketVersioning value that will be set via secret: %s", bucketVersioning) + log.Info(fmt.Sprintf("[%s] Bucket versioning from secret", reqID), zap.String("versioning", bucketVersioning)) } else if val, ok := params[constants.BucketVersioning]; ok && val != "" { enable := strings.ToLower(strings.TrimSpace(val)) if enable != "true" && enable != "false" { + log.Error(fmt.Sprintf("[%s] Invalid bucket versioning value in storage class", reqID), zap.String("value", val)) return nil, status.Error(codes.InvalidArgument, - fmt.Sprintf("Invalid bucketVersioning value in storage class: %s. Must be 'true' or 'false'", val)) + fmt.Sprintf("[%s] Invalid bucketVersioning value in storage class: %s. Must be 'true' or 'false'", reqID, val)) } bucketVersioning = enable - klog.Infof("BucketVersioning value that will be set via storage class params: %s", bucketVersioning) + log.Info(fmt.Sprintf("[%s] Bucket versioning from storage class", reqID), zap.String("versioning", bucketVersioning)) } creds, err := getObjectStorageCredentialsFromSecret(secretMap, cs.iamEndpoint) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in getting credentials %v", err)) + log.Error(fmt.Sprintf("[%s] Error getting credentials from secret", reqID), zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in getting credentials %v", reqID, err)) } - klog.Infof("cosEndpoint and locationConstraint getting paased to ObjectStorageSession: %s, %s", endPoint, locationConstraint) + log.Info(fmt.Sprintf("[%s] Creating object storage session", reqID), + zap.String("endpoint", endPoint), + zap.String("location_constraint", locationConstraint)) sess := cs.cosSession.NewObjectStorageSession(endPoint, locationConstraint, creds, cs.Logger) params["userProvidedBucket"] = "true" if bucketName != "" { // User Provided bucket. Check its existence and create if not present - klog.Infof("Bucket name provided: %v", bucketName) - klog.Infof("Check if the provided bucket already exists: %v", bucketName) + log.Info(fmt.Sprintf("[%s] Bucket name provided", reqID), zap.String("bucket_name", bucketName)) + log.Info(fmt.Sprintf("[%s] Checking if bucket already exists", reqID), zap.String("bucket_name", bucketName)) if err := sess.CheckBucketAccess(bucketName); err != nil { - klog.Infof("CreateVolume: bucket not accessible: %v, Creating new bucket with given name", err) + log.Info(fmt.Sprintf("[%s] Bucket not accessible, creating new bucket", reqID), + zap.String("bucket_name", bucketName), zap.Error(err)) err = createBucket(sess, bucketName, kpRootKeyCrn) if err != nil { - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("%v: %v", err, bucketName)) + log.Error(fmt.Sprintf("[%s] Failed to create bucket", reqID), + zap.String("bucket_name", bucketName), zap.Error(err)) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] %v: %v", reqID, err, bucketName)) } params["userProvidedBucket"] = "false" - klog.Infof("Created bucket: %s", bucketName) + log.Info(fmt.Sprintf("[%s] Created bucket successfully", reqID), zap.String("bucket_name", bucketName)) } if quotaLimitEnabled { quotaBytes := req.GetCapacityRange().GetRequiredBytes() resConfApikey := secretMap[constants.ResourceConfigApiKey] - klog.Infof("Applying hard quota of %d bytes to bucket %s", quotaBytes, bucketName) + log.Info(fmt.Sprintf("[%s] Applying hard quota to bucket", reqID), + zap.Int64("quota_bytes", quotaBytes), zap.String("bucket_name", bucketName)) err = sess.UpdateQuotaLimit(quotaBytes, resConfApikey, bucketName, endPoint, creds.IAMEndpoint) if err != nil { - klog.Errorf("Failed to set quota limit on bucket %s: %v", bucketName, err) + log.Error(fmt.Sprintf("[%s] Failed to set quota limit on bucket", reqID), + zap.String("bucket_name", bucketName), zap.Error(err)) if params["userProvidedBucket"] == "false" { if delErr := sess.DeleteBucket(bucketName); delErr != nil { - klog.Errorf("Failed to delete bucket %s after quota limit failure: %v", bucketName, delErr) + log.Error(fmt.Sprintf("[%s] Failed to delete bucket after quota limit failure", reqID), + zap.String("bucket_name", bucketName), zap.Error(delErr)) } } - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set bucket quota limit: %v", err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set bucket quota limit: %v", reqID, err)) } - klog.Infof("Successfully applied hard quota %d bytes to bucket %s", quotaBytes, bucketName) + log.Info(fmt.Sprintf("[%s] Successfully applied hard quota to bucket", reqID), + zap.Int64("quota_bytes", quotaBytes), zap.String("bucket_name", bucketName)) } if bucketVersioning != "" { enable := strings.ToLower(strings.TrimSpace(bucketVersioning)) == "true" - klog.Infof("Bucket versioning value evaluated to: %t", enable) + log.Info(fmt.Sprintf("[%s] Setting bucket versioning", reqID), + zap.Bool("enable", enable), zap.String("bucket_name", bucketName)) err := sess.SetBucketVersioning(bucketName, enable) if err != nil { + log.Error(fmt.Sprintf("[%s] Failed to set bucket versioning", reqID), + zap.Bool("enable", enable), zap.String("bucket_name", bucketName), zap.Error(err)) if params["userProvidedBucket"] == "false" { err1 := sess.DeleteBucket(bucketName) if err1 != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("cannot set versioning: %v and cannot delete bucket %s: %v", err, bucketName, err1)) + log.Error(fmt.Sprintf("[%s] Failed to delete bucket after versioning failure", reqID), + zap.String("bucket_name", bucketName), zap.Error(err1)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] cannot set versioning: %v and cannot delete bucket %s: %v", reqID, err, bucketName, err1)) } } - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set versioning %t for bucket %s: %v", enable, bucketName, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set versioning %t for bucket %s: %v", reqID, enable, bucketName, err)) } - klog.Infof("Bucket versioning set to %t for bucket %s", enable, bucketName) + log.Info(fmt.Sprintf("[%s] Bucket versioning set successfully", reqID), + zap.Bool("enable", enable), zap.String("bucket_name", bucketName)) } params["bucketName"] = bucketName } else { // Generate random temp bucket name based on volume id - klog.Infof("Bucket name not provided") + log.Info(fmt.Sprintf("[%s] Bucket name not provided, generating temp bucket", reqID)) tempBucketName := getTempBucketName(mounter, volumeID) if tempBucketName == "" { - klog.Errorf("CreateVolume: Unable to generate the bucket name") - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Unable to access the bucket: %v", tempBucketName)) + log.Error(fmt.Sprintf("[%s] Unable to generate temp bucket name", reqID)) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] Unable to access the bucket: %v", reqID, tempBucketName)) } + log.Info(fmt.Sprintf("[%s] Creating temp bucket", reqID), zap.String("temp_bucket_name", tempBucketName)) err = createBucket(sess, tempBucketName, kpRootKeyCrn) if err != nil { - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("%v: %v", err, tempBucketName)) + log.Error(fmt.Sprintf("[%s] Failed to create temp bucket", reqID), + zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] %v: %v", reqID, err, tempBucketName)) } if quotaLimitEnabled { quotaBytes := req.GetCapacityRange().GetRequiredBytes() resConfApikey := secretMap[constants.ResourceConfigApiKey] - klog.Infof("Applying hard quota of %d bytes to temp bucket %s", quotaBytes, tempBucketName) + log.Info(fmt.Sprintf("[%s] Applying hard quota to temp bucket", reqID), + zap.Int64("quota_bytes", quotaBytes), zap.String("temp_bucket_name", tempBucketName)) err = sess.UpdateQuotaLimit(quotaBytes, resConfApikey, tempBucketName, endPoint, creds.IAMEndpoint) if err != nil { - klog.Errorf("Failed to set quota limit on temp bucket %s: %v", tempBucketName, err) + log.Error(fmt.Sprintf("[%s] Failed to set quota limit on temp bucket", reqID), + zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) if delErr := sess.DeleteBucket(tempBucketName); delErr != nil { - klog.Errorf("Failed to delete temp bucket %s after quota limit failure: %v", tempBucketName, delErr) + log.Error(fmt.Sprintf("[%s] Failed to delete temp bucket after quota limit failure", reqID), + zap.String("temp_bucket_name", tempBucketName), zap.Error(delErr)) } - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set bucket quota limit: %v", err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set bucket quota limit: %v", reqID, err)) } - klog.Infof("Successfully applied hard quota %d bytes to temp bucket %s", quotaBytes, tempBucketName) + log.Info(fmt.Sprintf("[%s] Successfully applied hard quota to temp bucket", reqID), + zap.Int64("quota_bytes", quotaBytes), zap.String("temp_bucket_name", tempBucketName)) } if bucketVersioning != "" { enable := strings.ToLower(strings.TrimSpace(bucketVersioning)) == "true" - klog.Infof("Temp bucket versioning value evaluated to: %t", enable) + log.Info(fmt.Sprintf("[%s] Setting temp bucket versioning", reqID), + zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName)) err := sess.SetBucketVersioning(tempBucketName, enable) if err != nil { + log.Error(fmt.Sprintf("[%s] Failed to set temp bucket versioning", reqID), + zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) err1 := sess.DeleteBucket(tempBucketName) if err1 != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("cannot set versioning: %v and cannot delete temp bucket %s: %v", err, tempBucketName, err1)) + log.Error(fmt.Sprintf("[%s] Failed to delete temp bucket after versioning failure", reqID), + zap.String("temp_bucket_name", tempBucketName), zap.Error(err1)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] cannot set versioning: %v and cannot delete temp bucket %s: %v", reqID, err, tempBucketName, err1)) } - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set versioning %t for temp bucket %s: %v", enable, tempBucketName, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set versioning %t for temp bucket %s: %v", reqID, enable, tempBucketName, err)) } - klog.Infof("Bucket versioning set to %t for temp bucket %s", enable, tempBucketName) + log.Info(fmt.Sprintf("[%s] Temp bucket versioning set successfully", reqID), + zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName)) } - klog.Infof("Created temp bucket: %s", tempBucketName) + log.Info(fmt.Sprintf("[%s] Created temp bucket successfully", reqID), zap.String("temp_bucket_name", tempBucketName)) params["userProvidedBucket"] = "false" params["bucketName"] = tempBucketName } - klog.Infof("create volume: %v", volumeID) - //COS Endpoint, bucket, access keys will be stored in the csiProvisionerSecretName - //The other tunables will be SC Parameters like ibm.io/multireq-max and other + + log.Info(fmt.Sprintf("[%s] CreateVolume completed successfully", reqID), + zap.String("volume_id", volumeID), + zap.String("bucket_name", params["bucketName"]), + zap.Int64("capacity_bytes", req.GetCapacityRange().GetRequiredBytes())) return &csi.CreateVolumeResponse{ Volume: &csi.Volume{ From 5801c68dd8b93ef8454a59ace79add641ed27c5e Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 19 May 2026 15:05:21 +0530 Subject: [PATCH 03/64] implement comprehensive request ID tracking --- README.md | 46 +++++++ cos-csi-mounter/server/server.go | 63 ++++++--- pkg/driver/controllerserver.go | 225 +++++++++++++++++++++---------- pkg/driver/nodeserver.go | 209 ++++++++++++++++++++-------- pkg/mounter/mounter-rclone.go | 67 ++++++--- pkg/mounter/mounter-s3fs.go | 77 +++++++---- pkg/mounter/mounter.go | 63 +++++---- pkg/s3client/s3client.go | 138 ++++++++++++++----- 8 files changed, 632 insertions(+), 256 deletions(-) diff --git a/README.md b/README.md index d1d79835..274886a2 100644 --- a/README.md +++ b/README.md @@ -173,3 +173,49 @@ Collect logs using below commands to check failure messages 1. `oc logs cos-s3-csi-controller-0 -c cos-csi-provisioner` 2. `oc logs cos-s3-csi-driver-xxx -c cos-csi-driver` + +## Request ID Tracking + +The IBM Object CSI Driver implements comprehensive request ID tracking for end-to-end tracing of operations. Every CSI operation is assigned a unique UUID v4 identifier that flows through all components. + +### Key Features +- **Automatic Request ID Generation**: Every gRPC request gets a unique UUID v4 +- **End-to-End Propagation**: Request ID flows through CSI → S3Client → Mounter → cos-csi-mounter +- **Structured Logging**: All logs include request ID in both message text and structured fields +- **Cross-Component Tracing**: Track operations across controller, node, and mounter services + +### Quick Start + +Filter logs by request ID: +```bash +# Get logs for specific request +kubectl logs -n kube-system | grep "550e8400-e29b-41d4-a716-446655440000" + +# Using jq for JSON logs +kubectl logs -n kube-system | jq 'select(.request_id == "550e8400-...")' +``` + +Track complete operation flow: +```bash +# Extract request ID from initial log +REQUEST_ID=$(kubectl logs -n kube-system | \ + jq -r 'select(.msg | contains("CreateVolume started")) | .request_id' | head -1) + +# View all logs for that request +kubectl logs -n kube-system | jq "select(.request_id == \"$REQUEST_ID\")" +``` + +### Documentation +For comprehensive documentation on request ID tracking, troubleshooting, and best practices, see: +- [Request ID Tracking Guide](docs/REQUEST_ID_TRACKING.md) + +### Example Log Output +```json +{ + "level": "info", + "timestamp": "2024-01-15T10:30:45.123Z", + "msg": "[550e8400-e29b-41d4-a716-446655440000] CreateVolume started", + "request_id": "550e8400-e29b-41d4-a716-446655440000", + "volume_name": "pvc-abc123" +} +``` diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index 3c690dbe..1ae1ea0c 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -159,71 +159,96 @@ func main() { func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) gin.HandlerFunc { return func(c *gin.Context) { + // Extract request ID from HTTP header + reqID := c.GetHeader("X-Request-ID") + if reqID == "" { + reqID = "unknown" + } + log := logger.With(zap.String("request_id", reqID)) + var request MountRequest if err := c.BindJSON(&request); err != nil { - logger.Error("invalid request: ", zap.Error(err)) - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"}) + log.Error(fmt.Sprintf("[%s] Invalid request", reqID), zap.Error(err)) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid request", reqID)}) return } - logger.Info("New mount request with values:", zap.String("Bucket", request.Bucket), zap.String("Path", request.Path), zap.String("Mounter", request.Mounter), zap.Any("Args", request.Args)) + log.Info(fmt.Sprintf("[%s] New mount request", reqID), + zap.String("bucket", request.Bucket), + zap.String("path", request.Path), + zap.String("mounter", request.Mounter), + zap.Any("args", request.Args)) if request.Mounter != constants.S3FS && request.Mounter != constants.RClone { - logger.Error("invalid mounter", zap.Any("mounter", request.Mounter)) - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid mounter"}) + log.Error(fmt.Sprintf("[%s] Invalid mounter", reqID), zap.String("mounter", request.Mounter)) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid mounter", reqID)}) return } if request.Bucket == "" { - logger.Error("missing bucket in request") - c.JSON(http.StatusBadRequest, gin.H{"error": "missing bucket"}) + log.Error(fmt.Sprintf("[%s] Missing bucket in request", reqID)) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] missing bucket", reqID)}) return } // validate mounter args + log.Debug(fmt.Sprintf("[%s] Parsing mounter args", reqID)) args, err := parser.Parse(request) if err != nil { - logger.Error("failed to parse mounter args", zap.Any("mounter", request.Mounter), zap.Error(err)) - - c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid args for mounter: %v", err)}) + log.Error(fmt.Sprintf("[%s] Failed to parse mounter args", reqID), + zap.String("mounter", request.Mounter), zap.Error(err)) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid args for mounter: %v", reqID, err)}) return } + log.Info(fmt.Sprintf("[%s] Mounting bucket", reqID), + zap.String("path", request.Path), + zap.String("mounter", request.Mounter)) err = mounter.FuseMount(request.Path, request.Mounter, args) if err != nil { - logger.Error("mount failed: ", zap.Error(err)) - c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("mount failed: %v", err)}) + log.Error(fmt.Sprintf("[%s] Mount failed", reqID), zap.Error(err)) + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("[%s] mount failed: %v", reqID, err)}) return } - logger.Info("bucket mount is successful", zap.Any("bucket", request.Bucket), zap.Any("path", request.Path)) + log.Info(fmt.Sprintf("[%s] Bucket mount successful", reqID), + zap.String("bucket", request.Bucket), + zap.String("path", request.Path)) c.JSON(http.StatusOK, gin.H{"status": "success"}) } } func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { return func(c *gin.Context) { + // Extract request ID from HTTP header + reqID := c.GetHeader("X-Request-ID") + if reqID == "" { + reqID = "unknown" + } + log := logger.With(zap.String("request_id", reqID)) + var request struct { Path string `json:"path"` } if err := c.BindJSON(&request); err != nil { - logger.Error("invalid request: ", zap.Error(err)) - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"}) + log.Error(fmt.Sprintf("[%s] Invalid request", reqID), zap.Error(err)) + c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid request", reqID)}) return } - logger.Info("New unmount request with values: ", zap.String("Path", request.Path)) + log.Info(fmt.Sprintf("[%s] New unmount request", reqID), zap.String("path", request.Path)) + log.Info(fmt.Sprintf("[%s] Unmounting bucket", reqID), zap.String("path", request.Path)) err := mounter.FuseUnmount(request.Path) if err != nil { - logger.Error("unmount failed: ", zap.Error(err)) - c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("unmount failed :%v", err)}) + log.Error(fmt.Sprintf("[%s] Unmount failed", reqID), zap.Error(err)) + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("[%s] unmount failed: %v", reqID, err)}) return } - logger.Info("bucket unmount is successful", zap.Any("path", request.Path)) + log.Info(fmt.Sprintf("[%s] Bucket unmount successful", reqID), zap.String("path", request.Path)) c.JSON(http.StatusOK, gin.H{"status": "success"}) } } diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index 68bfb9b3..2bc18f05 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -260,10 +260,10 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol // User Provided bucket. Check its existence and create if not present log.Info(fmt.Sprintf("[%s] Bucket name provided", reqID), zap.String("bucket_name", bucketName)) log.Info(fmt.Sprintf("[%s] Checking if bucket already exists", reqID), zap.String("bucket_name", bucketName)) - if err := sess.CheckBucketAccess(bucketName); err != nil { + if err := sess.CheckBucketAccess(ctx, bucketName); err != nil { log.Info(fmt.Sprintf("[%s] Bucket not accessible, creating new bucket", reqID), zap.String("bucket_name", bucketName), zap.Error(err)) - err = createBucket(sess, bucketName, kpRootKeyCrn) + err = createBucket(ctx, sess, bucketName, kpRootKeyCrn, log) if err != nil { log.Error(fmt.Sprintf("[%s] Failed to create bucket", reqID), zap.String("bucket_name", bucketName), zap.Error(err)) @@ -279,12 +279,12 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol log.Info(fmt.Sprintf("[%s] Applying hard quota to bucket", reqID), zap.Int64("quota_bytes", quotaBytes), zap.String("bucket_name", bucketName)) - err = sess.UpdateQuotaLimit(quotaBytes, resConfApikey, bucketName, endPoint, creds.IAMEndpoint) + err = sess.UpdateQuotaLimit(ctx, quotaBytes, resConfApikey, bucketName, endPoint, creds.IAMEndpoint) if err != nil { log.Error(fmt.Sprintf("[%s] Failed to set quota limit on bucket", reqID), zap.String("bucket_name", bucketName), zap.Error(err)) if params["userProvidedBucket"] == "false" { - if delErr := sess.DeleteBucket(bucketName); delErr != nil { + if delErr := sess.DeleteBucket(ctx, bucketName); delErr != nil { log.Error(fmt.Sprintf("[%s] Failed to delete bucket after quota limit failure", reqID), zap.String("bucket_name", bucketName), zap.Error(delErr)) } @@ -300,12 +300,12 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol log.Info(fmt.Sprintf("[%s] Setting bucket versioning", reqID), zap.Bool("enable", enable), zap.String("bucket_name", bucketName)) - err := sess.SetBucketVersioning(bucketName, enable) + err := sess.SetBucketVersioning(ctx, bucketName, enable) if err != nil { log.Error(fmt.Sprintf("[%s] Failed to set bucket versioning", reqID), zap.Bool("enable", enable), zap.String("bucket_name", bucketName), zap.Error(err)) if params["userProvidedBucket"] == "false" { - err1 := sess.DeleteBucket(bucketName) + err1 := sess.DeleteBucket(ctx, bucketName) if err1 != nil { log.Error(fmt.Sprintf("[%s] Failed to delete bucket after versioning failure", reqID), zap.String("bucket_name", bucketName), zap.Error(err1)) @@ -328,7 +328,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] Unable to access the bucket: %v", reqID, tempBucketName)) } log.Info(fmt.Sprintf("[%s] Creating temp bucket", reqID), zap.String("temp_bucket_name", tempBucketName)) - err = createBucket(sess, tempBucketName, kpRootKeyCrn) + err = createBucket(ctx, sess, tempBucketName, kpRootKeyCrn, log) if err != nil { log.Error(fmt.Sprintf("[%s] Failed to create temp bucket", reqID), zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) @@ -341,11 +341,11 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol log.Info(fmt.Sprintf("[%s] Applying hard quota to temp bucket", reqID), zap.Int64("quota_bytes", quotaBytes), zap.String("temp_bucket_name", tempBucketName)) - err = sess.UpdateQuotaLimit(quotaBytes, resConfApikey, tempBucketName, endPoint, creds.IAMEndpoint) + err = sess.UpdateQuotaLimit(ctx, quotaBytes, resConfApikey, tempBucketName, endPoint, creds.IAMEndpoint) if err != nil { log.Error(fmt.Sprintf("[%s] Failed to set quota limit on temp bucket", reqID), zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) - if delErr := sess.DeleteBucket(tempBucketName); delErr != nil { + if delErr := sess.DeleteBucket(ctx, tempBucketName); delErr != nil { log.Error(fmt.Sprintf("[%s] Failed to delete temp bucket after quota limit failure", reqID), zap.String("temp_bucket_name", tempBucketName), zap.Error(delErr)) } @@ -360,11 +360,11 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol log.Info(fmt.Sprintf("[%s] Setting temp bucket versioning", reqID), zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName)) - err := sess.SetBucketVersioning(tempBucketName, enable) + err := sess.SetBucketVersioning(ctx, tempBucketName, enable) if err != nil { log.Error(fmt.Sprintf("[%s] Failed to set temp bucket versioning", reqID), zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) - err1 := sess.DeleteBucket(tempBucketName) + err1 := sess.DeleteBucket(ctx, tempBucketName) if err1 != nil { log.Error(fmt.Sprintf("[%s] Failed to delete temp bucket after versioning failure", reqID), zap.String("temp_bucket_name", tempBucketName), zap.Error(err1)) @@ -394,129 +394,186 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol }, nil } -func (cs *controllerServer) DeleteVolume(_ context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { +func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { + // Extract request ID from context + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] DeleteVolume started", reqID)) + modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in modifying requests %v", err)) + log.Error(fmt.Sprintf("[%s] Error modifying request", reqID), zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) } - klog.V(3).Infof("CSIControllerServer-DeleteVolume: Request: %v", modifiedRequest.(*csi.DeleteVolumeRequest)) + log.Debug(fmt.Sprintf("[%s] DeleteVolume request details", reqID), zap.Any("request", modifiedRequest.(*csi.DeleteVolumeRequest))) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } - klog.Infof("Deleting volume %v", volumeID) + log.Info(fmt.Sprintf("[%s] Deleting volume", reqID), zap.String("volume_id", volumeID)) + secretMap := req.GetSecrets() + log.Info(fmt.Sprintf("[%s] Secrets received", reqID), zap.Int("secret_count", len(secretMap))) endPoint := secretMap["cosEndpoint"] locationConstraint := secretMap["locationConstraint"] if len(secretMap) == 0 { - klog.Info("Did not find the secret that matches pvc name. Fetching custom secret from PVC annotations") + log.Info(fmt.Sprintf("[%s] No secret in request, fetching from PV", reqID)) pv, err := cs.Stats.GetPV(volumeID) if err != nil { + log.Error(fmt.Sprintf("[%s] Failed to get PV", reqID), zap.String("volume_id", volumeID), zap.Error(err)) return nil, err } - klog.Info("pv Resource details:\n\t", pv) + log.Debug(fmt.Sprintf("[%s] PV resource retrieved", reqID), zap.Any("pv", pv)) secretName := pv.Spec.CSI.NodePublishSecretRef.Name secretNamespace := pv.Spec.CSI.NodePublishSecretRef.Namespace if secretName == "" { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Secret details not found, could not fetch the secret %v", err)) + log.Error(fmt.Sprintf("[%s] Secret details not found in PV", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret details not found, could not fetch the secret", reqID)) } if secretNamespace == "" { - klog.Info("secret Namespace not found. trying to fetch the secret in default namespace") + log.Warn(fmt.Sprintf("[%s] Secret namespace not found, using default namespace", reqID)) secretNamespace = constants.DefaultNamespace } endPoint = pv.Spec.CSI.VolumeAttributes["cosEndpoint"] locationConstraint = pv.Spec.CSI.VolumeAttributes["locationConstraint"] - klog.Info("secret details found. secret-name: ", secretName, "\tsecret-namespace: ", secretNamespace) + log.Info(fmt.Sprintf("[%s] Secret details found", reqID), + zap.String("secret_name", secretName), + zap.String("secret_namespace", secretNamespace)) secret, err := cs.Stats.GetSecret(secretName, secretNamespace) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Secret resource not found %v", err)) + log.Error(fmt.Sprintf("[%s] Secret resource not found", reqID), zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) } secretMapCustom := parseCustomSecret(secret) - klog.Info("custom secret parameters parsed successfully, length of custom secret: ", len(secretMapCustom)) + log.Info(fmt.Sprintf("[%s] Custom secret parsed successfully", reqID), zap.Int("secret_param_count", len(secretMapCustom))) secretMap = secretMapCustom } creds, err := getObjectStorageCredentialsFromSecret(secretMap, cs.iamEndpoint) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in getting credentials %v", err)) + log.Error(fmt.Sprintf("[%s] Error getting credentials from secret", reqID), zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in getting credentials %v", reqID, err)) } + log.Info(fmt.Sprintf("[%s] Creating object storage session for deletion", reqID), + zap.String("endpoint", endPoint), + zap.String("location_constraint", locationConstraint)) sess := cs.cosSession.NewObjectStorageSession(endPoint, locationConstraint, creds, cs.Logger) bucketToDelete, err := cs.Stats.BucketToDelete(volumeID) if err != nil { + log.Warn(fmt.Sprintf("[%s] No bucket to delete or error getting bucket info", reqID), zap.Error(err)) return &csi.DeleteVolumeResponse{}, nil } if bucketToDelete != "" { - err = sess.DeleteBucket(bucketToDelete) + log.Info(fmt.Sprintf("[%s] Deleting bucket", reqID), zap.String("bucket_name", bucketToDelete)) + err = sess.DeleteBucket(ctx, bucketToDelete) if err != nil { - klog.V(3).Infof("Cannot delete temp bucket: %v; error msg: %v", bucketToDelete, err) + log.Warn(fmt.Sprintf("[%s] Cannot delete bucket", reqID), + zap.String("bucket_name", bucketToDelete), zap.Error(err)) + } else { + log.Info(fmt.Sprintf("[%s] Bucket deleted successfully", reqID), zap.String("bucket_name", bucketToDelete)) } - klog.Infof("End of bucket delete for %v", volumeID) + } else { + log.Info(fmt.Sprintf("[%s] No bucket to delete", reqID)) } + log.Info(fmt.Sprintf("[%s] DeleteVolume completed successfully", reqID), zap.String("volume_id", volumeID)) return &csi.DeleteVolumeResponse{}, nil } -func (cs *controllerServer) ControllerPublishVolume(_ context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { - klog.V(3).Infof("CSIControllerServer-ControllerPublishVolume: Request: %+v", req) - return nil, status.Error(codes.Unimplemented, "ControllerPublishVolume") +func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ControllerPublishVolume request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ControllerPublishVolume not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerPublishVolume", reqID)) } -func (cs *controllerServer) ControllerUnpublishVolume(_ context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) { - klog.V(3).Infof("CSIControllerServer-ControllerUnPublishVolume: Request: %+v", req) - return nil, status.Error(codes.Unimplemented, "ControllerUnpublishVolume") +func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ControllerUnpublishVolume request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ControllerUnpublishVolume not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerUnpublishVolume", reqID)) } -func (cs *controllerServer) ValidateVolumeCapabilities(_ context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) { - klog.V(3).Infof("ValidateVolumeCapabilities: Request: %+v", req) +func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] ValidateVolumeCapabilities started", reqID)) + log.Debug(fmt.Sprintf("[%s] ValidateVolumeCapabilities request", reqID), zap.Any("request", req)) // Validate Arguments volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } volCaps := req.GetVolumeCapabilities() if len(volCaps) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume capabilities missing in request") + log.Error(fmt.Sprintf("[%s] Volume capabilities missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capabilities missing in request", reqID)) } var confirmed *csi.ValidateVolumeCapabilitiesResponse_Confirmed if isValidVolumeCapabilities(volCaps) { + log.Info(fmt.Sprintf("[%s] Volume capabilities are valid", reqID), zap.String("volume_id", volumeID)) confirmed = &csi.ValidateVolumeCapabilitiesResponse_Confirmed{VolumeCapabilities: volCaps} + } else { + log.Warn(fmt.Sprintf("[%s] Volume capabilities are invalid", reqID), zap.String("volume_id", volumeID)) } + log.Info(fmt.Sprintf("[%s] ValidateVolumeCapabilities completed", reqID), zap.String("volume_id", volumeID)) return &csi.ValidateVolumeCapabilitiesResponse{ Confirmed: confirmed, }, nil } -func (cs *controllerServer) ListVolumes(_ context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { - klog.V(3).Infof("ListVolumes: Request: %+v", req) - return nil, status.Error(codes.Unimplemented, "ListVolumes") +func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ListVolumes request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ListVolumes not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListVolumes", reqID)) } -func (cs *controllerServer) GetCapacity(_ context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) { - klog.V(3).Infof("GetCapacity: Request: %+v", req) - return nil, status.Error(codes.Unimplemented, "GetCapacity") +func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] GetCapacity request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] GetCapacity not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] GetCapacity", reqID)) } -func (cs *controllerServer) ControllerGetCapabilities(_ context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { - klog.V(3).Infof("ControllerGetCapabilities: Request: %+v", req) +func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] ControllerGetCapabilities started", reqID)) + log.Debug(fmt.Sprintf("[%s] ControllerGetCapabilities request", reqID), zap.Any("request", req)) + var caps []*csi.ControllerServiceCapability for _, cap := range controllerCapabilities { c := &csi.ControllerServiceCapability{ @@ -528,37 +585,63 @@ func (cs *controllerServer) ControllerGetCapabilities(_ context.Context, req *cs } caps = append(caps, c) } + + log.Info(fmt.Sprintf("[%s] ControllerGetCapabilities completed", reqID), zap.Int("capability_count", len(caps))) return &csi.ControllerGetCapabilitiesResponse{Capabilities: caps}, nil } -func (cs *controllerServer) CreateSnapshot(_ context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { - klog.V(3).Infof("CreateSnapshot: Request: %+v", req) - return nil, status.Error(codes.Unimplemented, "CreateSnapshot") +func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] CreateSnapshot request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] CreateSnapshot not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] CreateSnapshot", reqID)) } -func (cs *controllerServer) DeleteSnapshot(_ context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { - klog.V(3).Infof("DeleteSnapshot: called with args %+v", req) - return nil, status.Error(codes.Unimplemented, "DeleteSnapshot") +func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] DeleteSnapshot request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] DeleteSnapshot not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] DeleteSnapshot", reqID)) } -func (cs *controllerServer) ListSnapshots(_ context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { - klog.V(3).Infof("ListSnapshots: called with args %+v", req) - return nil, status.Error(codes.Unimplemented, "ListSnapshots") +func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ListSnapshots request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ListSnapshots not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListSnapshots", reqID)) } -func (cs *controllerServer) ControllerExpandVolume(_ context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { - klog.V(3).Infof("ControllerExpandVolume: called with args %+v", req) - return nil, status.Error(codes.Unimplemented, "ControllerExpandVolume") +func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ControllerExpandVolume request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ControllerExpandVolume not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerExpandVolume", reqID)) } -func (cs *controllerServer) ControllerGetVolume(_ context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) { - klog.V(3).Infof("ControllerGetVolume: called with args %+v", req) - return nil, status.Error(codes.Unimplemented, "ControllerGetVolume") +func (cs *controllerServer) ControllerGetVolume(ctx context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ControllerGetVolume request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ControllerGetVolume not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerGetVolume", reqID)) } -func (cs *controllerServer) ControllerModifyVolume(_ context.Context, req *csi.ControllerModifyVolumeRequest) (*csi.ControllerModifyVolumeResponse, error) { - klog.V(3).Infof("ControllerModifyVolume: called with args %+v", req) - return nil, status.Error(codes.Unimplemented, "ControllerModifyVolume") +func (cs *controllerServer) ControllerModifyVolume(ctx context.Context, req *csi.ControllerModifyVolumeRequest) (*csi.ControllerModifyVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := cs.Logger.With(zap.String("request_id", reqID)) + + log.Debug(fmt.Sprintf("[%s] ControllerModifyVolume request", reqID), zap.Any("request", req)) + log.Info(fmt.Sprintf("[%s] ControllerModifyVolume not implemented", reqID)) + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerModifyVolume", reqID)) } func getObjectStorageCredentialsFromSecret(secretMap map[string]string, iamEP string) (*s3client.ObjectStorageCredentials, error) { @@ -702,22 +785,24 @@ func getTempBucketName(mounterType, volumeID string) string { return name } -func createBucket(sess s3client.ObjectStorageSession, bucketName, kpRootKeyCrn string) error { - msg, err := sess.CreateBucket(bucketName, kpRootKeyCrn) +func createBucket(ctx context.Context, sess s3client.ObjectStorageSession, bucketName, kpRootKeyCrn string, log *zap.Logger) error { + reqID := requestid.FromContext(ctx) + + msg, err := sess.CreateBucket(ctx, bucketName, kpRootKeyCrn) if msg != "" { - klog.Infof("Info:Create Volume module with user provided Bucket name: %v", msg) + log.Info(fmt.Sprintf("[%s] Bucket creation info", reqID), zap.String("message", msg)) } if err != nil { var apiErr smithy.APIError if errors.As(err, &apiErr) && apiErr.ErrorCode() == "BucketAlreadyExists" { - klog.Warning(fmt.Sprintf("bucket '%s' already exists", bucketName)) + log.Warn(fmt.Sprintf("[%s] Bucket already exists", reqID), zap.String("bucket", bucketName)) } else { - klog.Errorf("CreateVolume: Unable to create the bucket: %v", err) + log.Error(fmt.Sprintf("[%s] Unable to create bucket", reqID), zap.String("bucket", bucketName), zap.Error(err)) return errors.New("unable to create the bucket") } } - if err := sess.CheckBucketAccess(bucketName); err != nil { - klog.Errorf("CreateVolume: Unable to access the bucket: %v", err) + if err := sess.CheckBucketAccess(ctx, bucketName); err != nil { + log.Error(fmt.Sprintf("[%s] Unable to access bucket", reqID), zap.String("bucket", bucketName), zap.Error(err)) return errors.New("unable to access the bucket") } return nil diff --git a/pkg/driver/nodeserver.go b/pkg/driver/nodeserver.go index 2a858d5e..35a7967f 100644 --- a/pkg/driver/nodeserver.go +++ b/pkg/driver/nodeserver.go @@ -15,13 +15,15 @@ import ( "fmt" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/IBM/ibm-object-csi-driver/pkg/utils" "github.com/container-storage-interface/spec/lib/go/csi" + "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "k8s.io/klog/v2" ) // Implements Node Server csi.NodeServer @@ -42,66 +44,95 @@ type NodeServerConfig struct { TLSCipherSuite string } -func (ns *nodeServer) NodeStageVolume(_ context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { - klog.V(2).Infof("CSINodeServer-NodeStageVolume: Request %+v", req) +func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeStageVolume started", reqID)) + log.Debug(fmt.Sprintf("[%s] NodeStageVolume request", reqID), zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } stagingTargetPath := req.GetStagingTargetPath() if len(stagingTargetPath) == 0 { - return nil, status.Error(codes.InvalidArgument, "Target path missing in request") + log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } + log.Info(fmt.Sprintf("[%s] NodeStageVolume completed", reqID), + zap.String("volume_id", volumeID), + zap.String("staging_target_path", stagingTargetPath)) return &csi.NodeStageVolumeResponse{}, nil } -func (ns *nodeServer) NodeUnstageVolume(_ context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { - klog.V(2).Infof("CSINodeServer-NodeUnstageVolume: Request %+v", req) +func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeUnstageVolume started", reqID)) + log.Debug(fmt.Sprintf("[%s] NodeUnstageVolume request", reqID), zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } stagingTargetPath := req.GetStagingTargetPath() if len(stagingTargetPath) == 0 { - return nil, status.Error(codes.InvalidArgument, "Target path missing in request") + log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } + log.Info(fmt.Sprintf("[%s] NodeUnstageVolume completed", reqID), + zap.String("volume_id", volumeID), + zap.String("staging_target_path", stagingTargetPath)) return &csi.NodeUnstageVolumeResponse{}, nil } -func (ns *nodeServer) NodePublishVolume(_ context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { +func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodePublishVolume started", reqID)) + modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in modifying requests %v", err)) + log.Error(fmt.Sprintf("[%s] Error modifying request", reqID), zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) } - klog.V(2).Infof("CSINodeServer-NodePublishVolume: Request %v", modifiedRequest.(*csi.NodePublishVolumeRequest)) + log.Debug(fmt.Sprintf("[%s] NodePublishVolume request", reqID), zap.Any("request", modifiedRequest.(*csi.NodePublishVolumeRequest))) volumeMountGroup := req.GetVolumeCapability().GetMount().GetVolumeMountGroup() - klog.V(2).Infof("CSINodeServer-NodePublishVolume-: volumeMountGroup: %v", volumeMountGroup) + log.Debug(fmt.Sprintf("[%s] Volume mount group", reqID), zap.String("volume_mount_group", volumeMountGroup)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } targetPath := req.GetTargetPath() if len(targetPath) == 0 { - return nil, status.Error(codes.InvalidArgument, "Target path missing in request") + log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } if req.GetVolumeCapability() == nil { - return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request") + log.Error(fmt.Sprintf("[%s] Volume capability missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capability missing in request", reqID)) } + log.Info(fmt.Sprintf("[%s] Checking mount point", reqID), zap.String("target_path", targetPath)) err = ns.Stats.CheckMount(targetPath) if err != nil { - klog.Errorf("Can not validate target mount point: %s %v", targetPath, err) - return nil, status.Error(codes.Internal, err.Error()) + log.Error(fmt.Sprintf("[%s] Cannot validate target mount point", reqID), + zap.String("target_path", targetPath), zap.Error(err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } deviceID := "" @@ -112,11 +143,17 @@ func (ns *nodeServer) NodePublishVolume(_ context.Context, req *csi.NodePublishV readOnly := req.GetReadonly() attrib := req.GetVolumeContext() mountFlags := req.GetVolumeCapability().GetMount().GetMountFlags() - klog.V(2).Infof("-NodePublishVolume-: targetPath: %v\ndeviceID: %v\nreadonly: %v\nvolumeId: %v\nattributes: %v\nmountFlags: %v\n", - targetPath, deviceID, readOnly, volumeID, attrib, mountFlags) + log.Debug(fmt.Sprintf("[%s] NodePublishVolume parameters", reqID), + zap.String("target_path", targetPath), + zap.String("device_id", deviceID), + zap.Bool("readonly", readOnly), + zap.String("volume_id", volumeID), + zap.Any("attributes", attrib), + zap.Strings("mount_flags", mountFlags)) secretMap := req.GetSecrets() - klog.V(2).Infof("-NodePublishVolume-: length of req.GetSecrets() length: %v", len(secretMap)) + log.Info(fmt.Sprintf("[%s] Secrets received", reqID), zap.Int("secret_count", len(secretMap))) + secretMapCopy := make(map[string]string) for k, v := range secretMap { if k == "accessKey" || k == "secretKey" || k == "apiKey" || k == "kpRootKeyCRN" { @@ -125,132 +162,162 @@ func (ns *nodeServer) NodePublishVolume(_ context.Context, req *csi.NodePublishV } secretMapCopy[k] = v } - klog.V(2).Infof("-NodePublishVolume-: secretMap: %v", secretMapCopy) + log.Debug(fmt.Sprintf("[%s] Secret map (sanitized)", reqID), zap.Any("secret_map", secretMapCopy)) + if volumeMountGroup != "" { secretMap["gid"] = volumeMountGroup + log.Debug(fmt.Sprintf("[%s] Added volume mount group to secrets", reqID), zap.String("gid", volumeMountGroup)) } if len(secretMap["cosEndpoint"]) == 0 { secretMap["cosEndpoint"] = attrib["cosEndpoint"] + log.Debug(fmt.Sprintf("[%s] Using cosEndpoint from attributes", reqID), zap.String("cos_endpoint", secretMap["cosEndpoint"])) } if len(secretMap["locationConstraint"]) == 0 { secretMap["locationConstraint"] = attrib["locationConstraint"] + log.Debug(fmt.Sprintf("[%s] Using locationConstraint from attributes", reqID), zap.String("location_constraint", secretMap["locationConstraint"])) } if len(secretMap["cosEndpoint"]) == 0 { - return nil, status.Error(codes.InvalidArgument, "S3 Service endpoint not provided") + log.Error(fmt.Sprintf("[%s] S3 Service endpoint not provided", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] S3 Service endpoint not provided", reqID)) } if len(secretMap["iamEndpoint"]) == 0 { secretMap["iamEndpoint"] = ns.iamEndpoint + log.Debug(fmt.Sprintf("[%s] Using default IAM endpoint", reqID), zap.String("iam_endpoint", ns.iamEndpoint)) } // If bucket name wasn't provided by user, we use temp bucket created for volume. if secretMap["bucketName"] == "" { + log.Info(fmt.Sprintf("[%s] Bucket name not provided, fetching from PV", reqID)) tempBucketName, err := ns.Stats.GetBucketNameFromPV(volumeID) if err != nil { - klog.Errorf("Unable to fetch pv %v", err) - return nil, status.Error(codes.Internal, err.Error()) + log.Error(fmt.Sprintf("[%s] Unable to fetch PV", reqID), zap.String("volume_id", volumeID), zap.Error(err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } if tempBucketName == "" { - klog.Errorf("Unable to fetch bucket name from pv") - return nil, status.Error(codes.Internal, "unable to fetch bucket name from pv") + log.Error(fmt.Sprintf("[%s] Unable to fetch bucket name from PV", reqID)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] unable to fetch bucket name from pv", reqID)) } secretMap["bucketName"] = tempBucketName + log.Info(fmt.Sprintf("[%s] Using bucket from PV", reqID), zap.String("bucket_name", tempBucketName)) } var defaultParamsMap = map[string]string{ constants.CipherSuitesKey: ns.TLSCipherSuite, } + log.Info(fmt.Sprintf("[%s] Creating mounter object", reqID)) mounterObj := ns.Mounter.NewMounter(attrib, secretMap, mountFlags, defaultParamsMap) - klog.Info("-NodePublishVolume-: Mount") - if err = mounterObj.Mount("", targetPath); err != nil { - klog.Info("-Mount-: Error: ", err) + log.Info(fmt.Sprintf("[%s] Mounting volume", reqID), + zap.String("bucket_name", secretMap["bucketName"]), + zap.String("target_path", targetPath)) + if err = mounterObj.Mount(ctx, "", targetPath); err != nil { + log.Error(fmt.Sprintf("[%s] Mount failed", reqID), zap.Error(err)) return nil, err } - klog.Infof("s3: bucket %s successfully mounted to %s", secretMap["bucketName"], targetPath) + log.Info(fmt.Sprintf("[%s] NodePublishVolume completed successfully", reqID), + zap.String("bucket_name", secretMap["bucketName"]), + zap.String("target_path", targetPath)) return &csi.NodePublishVolumeResponse{}, nil } -func (ns *nodeServer) NodeUnpublishVolume(_ context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { - klog.V(2).Infof("CSINodeServer-NodeUnpublishVolume: Request: %+v", req) +func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeUnpublishVolume started", reqID)) + log.Debug(fmt.Sprintf("[%s] NodeUnpublishVolume request", reqID), zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } targetPath := req.GetTargetPath() if len(targetPath) == 0 { - return nil, status.Error(codes.InvalidArgument, "Target path missing in request") + log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } - klog.Infof("Unmounting target path %s", targetPath) + + log.Info(fmt.Sprintf("[%s] Unmounting target path", reqID), zap.String("target_path", targetPath)) attrib, err := ns.Stats.GetPVAttributes(volumeID) if err != nil { - return nil, status.Error(codes.NotFound, "Failed to get PV details") + log.Error(fmt.Sprintf("[%s] Failed to get PV details", reqID), zap.String("volume_id", volumeID), zap.Error(err)) + return nil, status.Error(codes.NotFound, fmt.Sprintf("[%s] Failed to get PV details", reqID)) } mounterObj := ns.Mounter.NewMounter(attrib, nil, nil, nil) - klog.Info("-NodeUnpublishVolume-: Unmount") - if err = mounterObj.Unmount(targetPath); err != nil { + log.Info(fmt.Sprintf("[%s] Unmounting volume", reqID)) + if err = mounterObj.Unmount(ctx, targetPath); err != nil { //TODO: Need to handle the case with non existing mount separately - https://github.com/IBM/ibm-object-csi-driver/issues/46 - klog.Infof("UNMOUNT ERROR: %v", err) - return nil, status.Error(codes.Internal, err.Error()) + log.Error(fmt.Sprintf("[%s] Unmount failed", reqID), zap.String("target_path", targetPath), zap.Error(err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } - klog.Infof("Successfully unmounted target path %s", targetPath) + log.Info(fmt.Sprintf("[%s] NodeUnpublishVolume completed successfully", reqID), zap.String("target_path", targetPath)) return &csi.NodeUnpublishVolumeResponse{}, nil } -func (ns *nodeServer) NodeGetVolumeStats(_ context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { - klog.V(2).Infof("NodeGetVolumeStats: Request: %+v", req) +func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeGetVolumeStats started", reqID)) + log.Debug(fmt.Sprintf("[%s] NodeGetVolumeStats request", reqID), zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") + log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } volumePath := req.VolumePath if volumePath == "" { - return nil, status.Error(codes.InvalidArgument, "Path Doesn't exist") + log.Error(fmt.Sprintf("[%s] Volume path doesn't exist", reqID)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Path Doesn't exist", reqID)) } - klog.V(2).Info("NodeGetVolumeStats: Start getting Stats") + log.Debug(fmt.Sprintf("[%s] Getting filesystem stats", reqID), zap.String("volume_path", volumePath)) // Making direct call to fs library for the sake of simplicity. That way we don't need to initialize VolumeStatsUtils. If there is a need for VolumeStatsUtils to grow bigger then we can use it _, capacity, _, inodes, inodesFree, inodesUsed, err := ns.Stats.FSInfo(volumePath) if err != nil { - data := map[string]string{"VolumeId": volumeID, "Error": err.Error()} - klog.Error("NodeGetVolumeStats: error occurred while getting volume stats ", data) + log.Error(fmt.Sprintf("[%s] Error getting volume stats", reqID), + zap.String("volume_id", volumeID), zap.Error(err)) return &csi.NodeGetVolumeStatsResponse{ VolumeCondition: &csi.VolumeCondition{ Abnormal: true, - Message: err.Error(), + Message: fmt.Sprintf("[%s] %v", reqID, err.Error()), }, }, nil } totalCap, err := ns.Stats.GetTotalCapacityFromPV(volumeID) if err != nil { + log.Error(fmt.Sprintf("[%s] Error getting total capacity from PV", reqID), zap.Error(err)) return nil, err } capAsInt64, converted := totalCap.AsInt64() if !converted { capAsInt64 = capacity + log.Warn(fmt.Sprintf("[%s] Could not convert capacity, using filesystem capacity", reqID), zap.Int64("capacity", capacity)) } - klog.Info("NodeGetVolumeStats: Total Capacity of Volume: ", capAsInt64) + log.Info(fmt.Sprintf("[%s] Total capacity of volume", reqID), zap.Int64("capacity", capAsInt64)) capUsed, err := ns.Stats.GetBucketUsage(volumeID) if err != nil { + log.Error(fmt.Sprintf("[%s] Error getting bucket usage", reqID), zap.Error(err)) return nil, err } @@ -274,16 +341,29 @@ func (ns *nodeServer) NodeGetVolumeStats(_ context.Context, req *csi.NodeGetVolu }, } - klog.V(2).Info("NodeGetVolumeStats: Volume Stats ", resp) + log.Info(fmt.Sprintf("[%s] NodeGetVolumeStats completed", reqID), + zap.Int64("total_bytes", capAsInt64), + zap.Int64("used_bytes", capUsed), + zap.Int64("total_inodes", inodes), + zap.Int64("used_inodes", inodesUsed)) return resp, nil } -func (ns *nodeServer) NodeExpandVolume(_ context.Context, _ *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { - return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, "NodeExpandVolume is not implemented") +func (ns *nodeServer) NodeExpandVolume(ctx context.Context, _ *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeExpandVolume not implemented", reqID)) + return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] NodeExpandVolume is not implemented", reqID)) } -func (ns *nodeServer) NodeGetCapabilities(_ context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { - klog.V(2).Infof("NodeGetCapabilities: Request: %+v", req) +func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeGetCapabilities started", reqID)) + log.Debug(fmt.Sprintf("[%s] NodeGetCapabilities request", reqID), zap.Any("request", req)) + var caps []*csi.NodeServiceCapability for _, cap := range nodeServerCapabilities { c := &csi.NodeServiceCapability{ @@ -295,11 +375,17 @@ func (ns *nodeServer) NodeGetCapabilities(_ context.Context, req *csi.NodeGetCap } caps = append(caps, c) } + + log.Info(fmt.Sprintf("[%s] NodeGetCapabilities completed", reqID), zap.Int("capability_count", len(caps))) return &csi.NodeGetCapabilitiesResponse{Capabilities: caps}, nil } -func (ns *nodeServer) NodeGetInfo(_ context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { - klog.V(3).Infof("NodeGetInfo: called with args %+v", req) +func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { + reqID := requestid.FromContext(ctx) + log := ns.Logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] NodeGetInfo started", reqID)) + log.Debug(fmt.Sprintf("[%s] NodeGetInfo request", reqID), zap.Any("request", req)) topology := &csi.Topology{ Segments: map[string]string{ @@ -312,6 +398,11 @@ func (ns *nodeServer) NodeGetInfo(_ context.Context, req *csi.NodeGetInfoRequest MaxVolumesPerNode: ns.MaxVolumesPerNode, AccessibleTopology: topology, } - klog.V(2).Info("NodeGetInfo: ", resp) + + log.Info(fmt.Sprintf("[%s] NodeGetInfo completed", reqID), + zap.String("node_id", ns.NodeID), + zap.Int64("max_volumes_per_node", ns.MaxVolumesPerNode), + zap.String("region", ns.Region), + zap.String("zone", ns.Zone)) return resp, nil } diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index e4b30b7b..cfc8f0a7 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -13,6 +13,7 @@ package mounter import ( "bufio" + "context" "crypto/sha256" "encoding/json" "fmt" @@ -22,8 +23,10 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" - "k8s.io/klog/v2" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "go.uber.org/zap" ) // Mounter interface defined in mounter.go @@ -57,8 +60,6 @@ var ( ) func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { - klog.Info("-newRcloneMounter-") - var ( val string check bool @@ -120,9 +121,6 @@ func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounte mounter.UID = secretMap["uid"] } - klog.Infof("newRcloneMounter args:\n\tbucketName: [%s]\n\tobjectPath: [%s]\n\tendPoint: [%s]\n\tlocationConstraint: [%s]\n\tauthType: [%s]", - mounter.BucketName, mounter.ObjectPath, mounter.EndPoint, mounter.LocConstraint, mounter.AuthType) - updatedOptions := updateMountOptions(mountOptions, secretMap) mounter.MountOptions = updatedOptions @@ -176,9 +174,12 @@ func updateMountOptions(dafaultMountOptions []string, secretMap map[string]strin return updatedOptions } -func (rclone *RcloneMounter) Mount(source string, target string) error { - klog.Info("-RcloneMounter Mount-") - klog.Infof("Mount args:\n\tsource: <%s>\n\ttarget: <%s>", source, target) +func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target string) error { + reqID := requestid.FromContext(ctx) + log := logger.WithRequestID(ctx) + + log.Info(fmt.Sprintf("[%s] RcloneMounter Mount started", reqID), + zap.String("source", source), zap.String("target", target)) var bucketName string var err error @@ -191,8 +192,10 @@ func (rclone *RcloneMounter) Mount(source string, target string) error { } configPathWithVolID := path.Join(configPath, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) + log.Debug(fmt.Sprintf("[%s] Creating rclone config", reqID), zap.String("config_path", configPathWithVolID)) + if err = createConfigWrap(configPathWithVolID, rclone); err != nil { - klog.Errorf("RcloneMounter Mount: Cannot create rclone config file %v", err) + log.Error(fmt.Sprintf("[%s] Cannot create rclone config file", reqID), zap.Error(err)) return err } @@ -203,55 +206,75 @@ func (rclone *RcloneMounter) Mount(source string, target string) error { bucketName = fmt.Sprintf("%s:%s", remote, rclone.BucketName) } + log.Info(fmt.Sprintf("[%s] Formulating mount options", reqID), + zap.String("bucket_name", bucketName), + zap.String("auth_type", rclone.AuthType)) args, wnOp := rclone.formulateMountOptions(bucketName, target, configPathWithVolID) if mountWorker { - klog.Info("Mount on Worker started...") + log.Info(fmt.Sprintf("[%s] Mount on Worker started", reqID)) jsonData, err := json.Marshal(wnOp) if err != nil { - klog.Fatalf("Error marshalling data: %v", err) + log.Error(fmt.Sprintf("[%s] Error marshalling data", reqID), zap.Error(err)) return err } payload := fmt.Sprintf(`{"path":"%s","bucket":"%s","mounter":"%s","args":%s}`, target, bucketName, constants.RClone, jsonData) - err = mounterRequest(payload, "http://unix/api/cos/mount") + log.Debug(fmt.Sprintf("[%s] Worker mounting payload", reqID), zap.String("payload", payload)) + + err = mounterRequest(ctx, payload, "http://unix/api/cos/mount", log) if err != nil { - klog.Error("failed to mount on worker...", err) + log.Error(fmt.Sprintf("[%s] Failed to mount on worker", reqID), zap.Error(err)) return err } + log.Info(fmt.Sprintf("[%s] RcloneMounter Mount completed successfully on worker", reqID)) return nil } - klog.Info("NodeServer Mounting...") - return rclone.MounterUtils.FuseMount(target, constants.RClone, args) + + log.Info(fmt.Sprintf("[%s] NodeServer mounting", reqID)) + err = rclone.MounterUtils.FuseMount(target, constants.RClone, args) + if err != nil { + log.Error(fmt.Sprintf("[%s] FuseMount failed", reqID), zap.Error(err)) + } else { + log.Info(fmt.Sprintf("[%s] RcloneMounter Mount completed successfully", reqID)) + } + return err } -func (rclone *RcloneMounter) Unmount(target string) error { - klog.Info("-RcloneMounter Unmount-") +func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { + reqID := requestid.FromContext(ctx) + log := logger.WithRequestID(ctx) + + log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount started", reqID), zap.String("target", target)) if mountWorker { - klog.Info("Unmount on Worker started...") + log.Info(fmt.Sprintf("[%s] Unmount on Worker started", reqID)) payload := fmt.Sprintf(`{"path":"%s"}`, target) - err := mounterRequest(payload, "http://unix/api/cos/unmount") + err := mounterRequest(ctx, payload, "http://unix/api/cos/unmount", log) if err != nil { - klog.Error("failed to unmount on worker...", err) + log.Error(fmt.Sprintf("[%s] Failed to unmount on worker", reqID), zap.Error(err)) return err } removeConfigFile(constants.MounterConfigPathOnHost, target) + log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount completed successfully on worker", reqID)) return nil } - klog.Info("NodeServer Unmounting...") + + log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) err := rclone.MounterUtils.FuseUnmount(target) if err != nil { + log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) return err } removeConfigFile(constants.MounterConfigPathOnPodRclone, target) + log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount completed successfully", reqID)) return nil } diff --git a/pkg/mounter/mounter-s3fs.go b/pkg/mounter/mounter-s3fs.go index 3a5e55b7..d66dc09d 100644 --- a/pkg/mounter/mounter-s3fs.go +++ b/pkg/mounter/mounter-s3fs.go @@ -12,6 +12,7 @@ package mounter import ( + "context" "crypto/sha256" "encoding/json" "fmt" @@ -21,8 +22,10 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" - "k8s.io/klog/v2" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "go.uber.org/zap" ) // Mounter interface defined in mounter.go @@ -51,8 +54,6 @@ var ( ) func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils, defaultParams map[string]string) Mounter { - klog.Info("-newS3fsMounter-") - var ( val string check bool @@ -100,9 +101,6 @@ func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterU mounter.AuthType = "hmac" } - klog.Infof("newS3fsMounter args:\n\tbucketName: [%s]\n\tobjectPath: [%s]\n\tendPoint: [%s]\n\tlocationConstraint: [%s]\n\tauthType: [%s]\n\tkpRootKeyCrn: [%s]", - mounter.BucketName, mounter.ObjectPath, mounter.EndPoint, mounter.LocConstraint, mounter.AuthType, mounter.KpRootKeyCrn) - updatedOptions := updateS3FSMountOptions(mountOptions, secretMap, defaultParams) mounter.MountOptions = updatedOptions @@ -111,9 +109,12 @@ func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterU return mounter } -func (s3fs *S3fsMounter) Mount(source string, target string) error { - klog.Info("-S3FSMounter Mount-") - klog.Infof("Mount args:\n\tsource: <%s>\n\ttarget: <%s>", source, target) +func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string) error { + reqID := requestid.FromContext(ctx) + log := logger.WithRequestID(ctx) + + log.Info(fmt.Sprintf("[%s] S3FSMounter Mount started", reqID), + zap.String("source", source), zap.String("target", target)) var s3fsCredDir string if mountWorker { @@ -129,22 +130,23 @@ func (s3fs *S3fsMounter) Mount(source string, target string) error { metaPath := path.Join(s3fsCredDir, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) if pathExist, err = checkPath(metaPath); err != nil { - klog.Errorf("S3FSMounter Mount: Cannot stat directory %s: %v", metaPath, err) - return fmt.Errorf("S3FSMounter Mount: Cannot stat directory %s: %v", metaPath, err) + log.Error(fmt.Sprintf("[%s] Cannot stat directory", reqID), zap.String("meta_path", metaPath), zap.Error(err)) + return fmt.Errorf("[%s] S3FSMounter Mount: Cannot stat directory %s: %v", reqID, metaPath, err) } if !pathExist { + log.Debug(fmt.Sprintf("[%s] Creating meta directory", reqID), zap.String("meta_path", metaPath)) if err = MakeDir(metaPath, 0755); // #nosec G301: used for s3fs err != nil { - klog.Errorf("S3FSMounter Mount: Cannot create directory %s: %v", metaPath, err) - return fmt.Errorf("S3FSMounter Mount: Cannot create directory %s: %v", metaPath, err) + log.Error(fmt.Sprintf("[%s] Cannot create directory", reqID), zap.String("meta_path", metaPath), zap.Error(err)) + return fmt.Errorf("[%s] S3FSMounter Mount: Cannot create directory %s: %v", reqID, metaPath, err) } } passwdFile := path.Join(metaPath, passFile) if err = writePassWrap(passwdFile, s3fs.AccessKeys); err != nil { - klog.Errorf("S3FSMounter Mount: Cannot create file %s: %v", passwdFile, err) - return fmt.Errorf("S3FSMounter Mount: Cannot create file %s: %v", passwdFile, err) + log.Error(fmt.Sprintf("[%s] Cannot create password file", reqID), zap.String("passwd_file", passwdFile), zap.Error(err)) + return fmt.Errorf("[%s] S3FSMounter Mount: Cannot create file %s: %v", reqID, passwdFile, err) } if s3fs.ObjectPath != "" { @@ -157,58 +159,75 @@ func (s3fs *S3fsMounter) Mount(source string, target string) error { bucketName = s3fs.BucketName } + log.Info(fmt.Sprintf("[%s] Formulating mount options", reqID), + zap.String("bucket_name", bucketName), + zap.String("auth_type", s3fs.AuthType)) args, wnOp := s3fs.formulateMountOptions(bucketName, target, passwdFile) if mountWorker { - klog.Info(" Mount on Worker started...") + log.Info(fmt.Sprintf("[%s] Mount on Worker started", reqID)) jsonData, err := json.Marshal(wnOp) if err != nil { - klog.Fatalf("Error marshalling data: %v", err) + log.Error(fmt.Sprintf("[%s] Error marshalling data", reqID), zap.Error(err)) return err } payload := fmt.Sprintf(`{"path":"%s","bucket":"%s","mounter":"%s","args":%s}`, target, bucketName, constants.S3FS, jsonData) - klog.Info("Worker Mounting Payload...", payload) + log.Debug(fmt.Sprintf("[%s] Worker mounting payload", reqID), zap.String("payload", payload)) - err = mounterRequest(payload, "http://unix/api/cos/mount") + err = mounterRequest(ctx, payload, "http://unix/api/cos/mount", log) if err != nil { - klog.Error("failed to mount on worker...", err) + log.Error(fmt.Sprintf("[%s] Failed to mount on worker", reqID), zap.Error(err)) return err } + log.Info(fmt.Sprintf("[%s] S3FSMounter Mount completed successfully on worker", reqID)) return nil } - klog.Info("NodeServer Mounting...") - return s3fs.MounterUtils.FuseMount(target, constants.S3FS, args) + + log.Info(fmt.Sprintf("[%s] NodeServer mounting", reqID)) + err = s3fs.MounterUtils.FuseMount(target, constants.S3FS, args) + if err != nil { + log.Error(fmt.Sprintf("[%s] FuseMount failed", reqID), zap.Error(err)) + } else { + log.Info(fmt.Sprintf("[%s] S3FSMounter Mount completed successfully", reqID)) + } + return err } -func (s3fs *S3fsMounter) Unmount(target string) error { - klog.Info("-S3FSMounter Unmount-") - klog.Infof("Unmount args:\n\ttarget: <%s>", target) +func (s3fs *S3fsMounter) Unmount(ctx context.Context, target string) error { + reqID := requestid.FromContext(ctx) + log := logger.WithRequestID(ctx) + + log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount started", reqID), zap.String("target", target)) if mountWorker { - klog.Info("Unmount on Worker started...") + log.Info(fmt.Sprintf("[%s] Unmount on Worker started", reqID)) payload := fmt.Sprintf(`{"path":"%s"}`, target) - err := mounterRequest(payload, "http://unix/api/cos/unmount") + err := mounterRequest(ctx, payload, "http://unix/api/cos/unmount", log) if err != nil { - klog.Error("failed to unmount on worker...", err) + log.Error(fmt.Sprintf("[%s] Failed to unmount on worker", reqID), zap.Error(err)) return err } removeFile(constants.MounterConfigPathOnHost, target) + log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount completed successfully on worker", reqID)) return nil } - klog.Info("NodeServer Unmounting...") + + log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) err := s3fs.MounterUtils.FuseUnmount(target) if err != nil { + log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) return err } removeFile(constants.MounterConfigPathOnPodS3fs, target) + log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount completed successfully", reqID)) return nil } diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go index 533e9eae..28deda9b 100644 --- a/pkg/mounter/mounter.go +++ b/pkg/mounter/mounter.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "io" "net" "net/http" @@ -13,15 +14,20 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "k8s.io/klog/v2" ) var ( - mountWorker = true - mounterRequest = createCOSCSIMounterRequest + mountWorker = true + // mounterRequest is a function variable that can be overridden for testing + mounterRequest = func(ctx context.Context, payload string, url string, log *zap.Logger) error { + return createCOSCSIMounterRequest(ctx, payload, url, log) + } MakeDir = os.MkdirAll CreateFile = os.Create @@ -31,8 +37,8 @@ var ( ) type Mounter interface { - Mount(source string, target string) error - Unmount(target string) error + Mount(ctx context.Context, source string, target string) error + Unmount(ctx context.Context, target string) error } type CSIMounterFactory struct{} @@ -46,7 +52,6 @@ func NewCSIMounterFactory() *CSIMounterFactory { } func (s *CSIMounterFactory) NewMounter(attrib map[string]string, secretMap map[string]string, mountFlags []string, defaultMOMap map[string]string) Mounter { - klog.Info("-NewMounter-") var mounter, val string var check bool @@ -127,16 +132,19 @@ func writePass(pwFileName string, pwFileContent string) error { return nil } -func createCOSCSIMounterRequest(payload string, url string) error { +func createCOSCSIMounterRequest(ctx context.Context, payload string, url string, log *zap.Logger) error { + reqID := requestid.FromContext(ctx) + // Get socket path socketPath := os.Getenv(constants.COSCSIMounterSocketPathEnv) if socketPath == "" { socketPath = constants.COSCSIMounterSocketPath } - klog.Infof("COS CSI Mounter Socket Path: %s", socketPath) + log.Info(fmt.Sprintf("[%s] COS CSI Mounter Socket Path", reqID), zap.String("socket_path", socketPath)) err := isGRPCServerAvailable(socketPath) if err != nil { + log.Error(fmt.Sprintf("[%s] COS CSI Mounter service not available", reqID), zap.Error(err)) return err } @@ -156,58 +164,67 @@ func createCOSCSIMounterRequest(payload string, url string) error { // Create POST request req, err := http.NewRequest("POST", url, strings.NewReader(payload)) if err != nil { + log.Error(fmt.Sprintf("[%s] Failed to create HTTP request", reqID), zap.Error(err)) return err } req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Request-ID", reqID) // Add request ID to HTTP header + + log.Info(fmt.Sprintf("[%s] Sending request to cos-csi-mounter", reqID), zap.String("url", url)) response, err := client.Do(req) if err != nil { + log.Error(fmt.Sprintf("[%s] Failed to send request to cos-csi-mounter", reqID), zap.Error(err)) return err } defer func() { if err := response.Body.Close(); err != nil { - klog.Errorf("failed to close response body: %v", err) + log.Error(fmt.Sprintf("[%s] Failed to close response body", reqID), zap.Error(err)) } }() body, err := io.ReadAll(response.Body) if err != nil { + log.Error(fmt.Sprintf("[%s] Failed to read response body", reqID), zap.Error(err)) return err } responseBody := string(body) - klog.Infof("response from cos-csi-mounter -> Response body: %s, Response code: %v", responseBody, response.StatusCode) + log.Info(fmt.Sprintf("[%s] Response from cos-csi-mounter", reqID), + zap.String("response_body", responseBody), + zap.Int("status_code", response.StatusCode)) if response.StatusCode != http.StatusOK { - return parseGRPCResponse(response.StatusCode, responseBody) + return parseGRPCResponse(reqID, response.StatusCode, responseBody) } return nil } // parseGRPCResponse takes both response body and error code and frames error message -func parseGRPCResponse(code int, response string) error { +func parseGRPCResponse(reqID string, code int, response string) error { errMsg := parseErrFromResponse(response) + errMsgWithReqID := fmt.Sprintf("[%s] %s", reqID, errMsg) switch code { case http.StatusBadRequest: - return status.Error(codes.InvalidArgument, errMsg) + return status.Error(codes.InvalidArgument, errMsgWithReqID) case http.StatusNotFound: - return status.Error(codes.NotFound, errMsg) + return status.Error(codes.NotFound, errMsgWithReqID) case http.StatusConflict: - return status.Error(codes.AlreadyExists, errMsg) + return status.Error(codes.AlreadyExists, errMsgWithReqID) case http.StatusForbidden: - return status.Error(codes.PermissionDenied, errMsg) + return status.Error(codes.PermissionDenied, errMsgWithReqID) case http.StatusTooManyRequests: - return status.Error(codes.ResourceExhausted, errMsg) + return status.Error(codes.ResourceExhausted, errMsgWithReqID) case http.StatusNotImplemented: - return status.Error(codes.Unimplemented, errMsg) + return status.Error(codes.Unimplemented, errMsgWithReqID) case http.StatusInternalServerError: - return status.Error(codes.Internal, errMsg) + return status.Error(codes.Internal, errMsgWithReqID) case http.StatusServiceUnavailable: - return status.Error(codes.Unavailable, errMsg) + return status.Error(codes.Unavailable, errMsgWithReqID) case http.StatusUnauthorized: - return status.Error(codes.Unauthenticated, errMsg) + return status.Error(codes.Unauthenticated, errMsgWithReqID) default: - return status.Error(codes.Unknown, errMsg) + return status.Error(codes.Unknown, errMsgWithReqID) } } @@ -231,7 +248,7 @@ func parseErrFromResponse(response string) string { var errFromResp map[string]string err := json.Unmarshal([]byte(response), &errFromResp) if err != nil { - klog.Warning("failed to unmarshal response from server", err) + // Can't log here as we don't have logger context, just return the response return response } val, exists := errFromResp["error"] diff --git a/pkg/s3client/s3client.go b/pkg/s3client/s3client.go index da87399e..815cc5e5 100644 --- a/pkg/s3client/s3client.go +++ b/pkg/s3client/s3client.go @@ -17,6 +17,7 @@ package s3client import ( + "context" "fmt" "strings" @@ -29,6 +30,7 @@ import ( "github.com/IBM/ibm-cos-sdk-go/aws/session" "github.com/IBM/ibm-cos-sdk-go/service/s3" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "go.uber.org/zap" ) @@ -53,20 +55,20 @@ type ObjectStorageCredentials struct { // ObjectStorageSession is an interface of an object store session type ObjectStorageSession interface { // CheckBucketAccess method check that a bucket can be accessed - CheckBucketAccess(bucket string) error + CheckBucketAccess(ctx context.Context, bucket string) error // CheckObjectPathExistence method checks that object-path exists inside bucket - CheckObjectPathExistence(bucket, objectpath string) (bool, error) + CheckObjectPathExistence(ctx context.Context, bucket, objectpath string) (bool, error) // CreateBucket methods creates a new bucket - CreateBucket(bucket, kpRootKeyCrn string) (string, error) + CreateBucket(ctx context.Context, bucket, kpRootKeyCrn string) (string, error) // DeleteBucket methods deletes a bucket (with all of its objects) - DeleteBucket(bucket string) error + DeleteBucket(ctx context.Context, bucket string) error - SetBucketVersioning(bucket string, enable bool) error + SetBucketVersioning(ctx context.Context, bucket string, enable bool) error - UpdateQuotaLimit(quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error + UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error } // COSSessionFactory represents a COS (S3) session factory @@ -115,80 +117,115 @@ func (f *defaultRCClientFactory) NewResourceConfigurationV1(options *rc.Resource return rc.NewResourceConfigurationV1(options) } -func (s *COSSession) CheckBucketAccess(bucket string) error { +func (s *COSSession) CheckBucketAccess(ctx context.Context, bucket string) error { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] CheckBucketAccess started", reqID), zap.String("bucket", bucket)) _, err := s.svc.HeadBucket(&s3.HeadBucketInput{ Bucket: aws.String(bucket), }) + if err != nil { + log.Error(fmt.Sprintf("[%s] CheckBucketAccess failed", reqID), zap.String("bucket", bucket), zap.Error(err)) + } else { + log.Info(fmt.Sprintf("[%s] CheckBucketAccess completed", reqID), zap.String("bucket", bucket)) + } return err } -func (s *COSSession) CheckObjectPathExistence(bucket string, objectpath string) (bool, error) { - s.logger.Info("CheckObjectPathExistence args", zap.String("bucket", bucket), zap.String("objectpath", objectpath)) +func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string, objectpath string) (bool, error) { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] CheckObjectPathExistence started", reqID), + zap.String("bucket", bucket), zap.String("objectpath", objectpath)) + objectpath = strings.TrimPrefix(objectpath, "/") if !strings.HasSuffix(objectpath, "/") { objectpath = objectpath + "/" } + resp, err := s.svc.ListObjectsV2(&s3.ListObjectsV2Input{ Bucket: aws.String(bucket), MaxKeys: aws.Int64(1), Prefix: aws.String(objectpath), }) if err != nil { - s.logger.Error("cannot list bucket", zap.String("bucket", bucket)) - return false, fmt.Errorf("cannot list bucket '%s': %v", bucket, err) + log.Error(fmt.Sprintf("[%s] Cannot list bucket", reqID), zap.String("bucket", bucket), zap.Error(err)) + return false, fmt.Errorf("[%s] cannot list bucket '%s': %v", reqID, bucket, err) } + + exists := false if len(resp.Contents) == 1 { object := *(resp.Contents[0].Key) if (object == objectpath) || (strings.TrimSuffix(object, "/") == objectpath) { - return true, nil + exists = true } } - return false, nil + + log.Info(fmt.Sprintf("[%s] CheckObjectPathExistence completed", reqID), + zap.String("bucket", bucket), zap.String("objectpath", objectpath), zap.Bool("exists", exists)) + return exists, nil } -func (s *COSSession) CreateBucket(bucket, kpRootKeyCrn string) (res string, err error) { +func (s *COSSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn string) (res string, err error) { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] CreateBucket started", reqID), + zap.String("bucket", bucket), + zap.Bool("encryption_enabled", kpRootKeyCrn != "")) + if kpRootKeyCrn != "" { + log.Debug(fmt.Sprintf("[%s] Creating bucket with KP encryption", reqID), zap.String("bucket", bucket)) _, err = s.svc.CreateBucket(&s3.CreateBucketInput{ Bucket: aws.String(bucket), IBMSSEKPCustomerRootKeyCrn: aws.String(kpRootKeyCrn), IBMSSEKPEncryptionAlgorithm: aws.String(constants.KPEncryptionAlgorithm), }) } else { + log.Debug(fmt.Sprintf("[%s] Creating bucket without encryption", reqID), zap.String("bucket", bucket)) _, err = s.svc.CreateBucket(&s3.CreateBucketInput{ Bucket: aws.String(bucket), }) } if err != nil { - // TODO - // CreateVolume: Unable to create the bucket: %BucketAlreadyExists: - // The requested bucket name is not available. The bucket namespace is shared by all users of the system. - // Please select a different name and try again. - if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "BucketAlreadyOwnedByYou" { - s.logger.Warn("bucket already exists", zap.String("bucket", bucket)) - return fmt.Sprintf("bucket '%s' already exists", bucket), nil + log.Warn(fmt.Sprintf("[%s] Bucket already exists", reqID), zap.String("bucket", bucket)) + return fmt.Sprintf("[%s] bucket '%s' already exists", reqID, bucket), nil } + log.Error(fmt.Sprintf("[%s] CreateBucket failed", reqID), zap.String("bucket", bucket), zap.Error(err)) return "", err } + log.Info(fmt.Sprintf("[%s] CreateBucket completed successfully", reqID), zap.String("bucket", bucket)) return "", nil } -func (s *COSSession) DeleteBucket(bucket string) error { +func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] DeleteBucket started", reqID), zap.String("bucket", bucket)) + resp, err := s.svc.ListObjects(&s3.ListObjectsInput{ Bucket: aws.String(bucket), }) if err != nil { if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "NoSuchBucket" { - s.logger.Warn("bucket already deleted", zap.String("bucket", bucket)) + log.Warn(fmt.Sprintf("[%s] Bucket already deleted", reqID), zap.String("bucket", bucket)) return nil } - - return fmt.Errorf("cannot list bucket '%s': %v", bucket, err) + log.Error(fmt.Sprintf("[%s] Cannot list bucket", reqID), zap.String("bucket", bucket), zap.Error(err)) + return fmt.Errorf("[%s] cannot list bucket '%s': %v", reqID, bucket, err) } + objectCount := len(resp.Contents) + log.Info(fmt.Sprintf("[%s] Deleting objects from bucket", reqID), + zap.String("bucket", bucket), zap.Int("object_count", objectCount)) + for _, key := range resp.Contents { _, err = s.svc.DeleteObject(&s3.DeleteObjectInput{ Bucket: aws.String(bucket), @@ -196,23 +233,37 @@ func (s *COSSession) DeleteBucket(bucket string) error { }) if err != nil { - return fmt.Errorf("cannot delete object %s/%s: %v", bucket, *key.Key, err) + log.Error(fmt.Sprintf("[%s] Cannot delete object", reqID), + zap.String("bucket", bucket), zap.String("key", *key.Key), zap.Error(err)) + return fmt.Errorf("[%s] cannot delete object %s/%s: %v", reqID, bucket, *key.Key, err) } } + log.Info(fmt.Sprintf("[%s] Deleting bucket", reqID), zap.String("bucket", bucket)) _, err = s.svc.DeleteBucket(&s3.DeleteBucketInput{ Bucket: aws.String(bucket), }) + if err != nil { + log.Error(fmt.Sprintf("[%s] DeleteBucket failed", reqID), zap.String("bucket", bucket), zap.Error(err)) + } else { + log.Info(fmt.Sprintf("[%s] DeleteBucket completed successfully", reqID), zap.String("bucket", bucket)) + } return err } -func (s *COSSession) SetBucketVersioning(bucket string, enable bool) error { +func (s *COSSession) SetBucketVersioning(ctx context.Context, bucket string, enable bool) error { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + status := s3.BucketVersioningStatusSuspended if enable { status = s3.BucketVersioningStatusEnabled } - s.logger.Info("Setting versioning for bucket", zap.String("bucket", bucket), zap.Bool("enable", enable)) + + log.Info(fmt.Sprintf("[%s] SetBucketVersioning started", reqID), + zap.String("bucket", bucket), zap.Bool("enable", enable)) + _, err := s.svc.PutBucketVersioning(&s3.PutBucketVersioningInput{ Bucket: aws.String(bucket), VersioningConfiguration: &s3.VersioningConfiguration{ @@ -220,10 +271,13 @@ func (s *COSSession) SetBucketVersioning(bucket string, enable bool) error { }, }) if err != nil { - s.logger.Error("Failed to set versioning", zap.String("bucket", bucket), zap.Bool("enable", enable), zap.Error(err)) - return fmt.Errorf("failed to set versioning to %v for bucket '%s': %v", enable, bucket, err) + log.Error(fmt.Sprintf("[%s] SetBucketVersioning failed", reqID), + zap.String("bucket", bucket), zap.Bool("enable", enable), zap.Error(err)) + return fmt.Errorf("[%s] failed to set versioning to %v for bucket '%s': %v", reqID, enable, bucket, err) } - s.logger.Info("Versioning set successfully for bucket", zap.String("bucket", bucket), zap.Bool("enable", enable)) + + log.Info(fmt.Sprintf("[%s] SetBucketVersioning completed successfully", reqID), + zap.String("bucket", bucket), zap.Bool("enable", enable)) return nil } @@ -256,12 +310,20 @@ func (s *COSSessionFactory) NewObjectStorageSession(endpoint, locationConstraint } } -func (s *COSSession) UpdateQuotaLimit(quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { +func (s *COSSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + + log.Info(fmt.Sprintf("[%s] UpdateQuotaLimit started", reqID), + zap.String("bucket", bucketName), zap.Int64("quota", quota)) + var configEndpoint string if strings.Contains(strings.ToLower(cosEndpoint), "private") { configEndpoint = constants.ResourceConfigEPPrivate + log.Debug(fmt.Sprintf("[%s] Using private resource config endpoint", reqID)) } else { configEndpoint = constants.ResourceConfigEPDirect + log.Debug(fmt.Sprintf("[%s] Using direct resource config endpoint", reqID)) } iamTokenURL := iamEndpoint + "/identity/token" @@ -271,12 +333,14 @@ func (s *COSSession) UpdateQuotaLimit(quota int64, apiKey, bucketName, cosEndpoi URL: iamTokenURL, } + log.Debug(fmt.Sprintf("[%s] Creating resource configuration service", reqID)) service, err := s.rcClientFactory.NewResourceConfigurationV1(&rc.ResourceConfigurationV1Options{ Authenticator: authenticator, URL: configEndpoint, }) if err != nil { - return fmt.Errorf("failed to create resource configuration service: %w", err) + log.Error(fmt.Sprintf("[%s] Failed to create resource configuration service", reqID), zap.Error(err)) + return fmt.Errorf("[%s] failed to create resource configuration service: %w", reqID, err) } bucketPatch := make(map[string]interface{}) @@ -287,10 +351,16 @@ func (s *COSSession) UpdateQuotaLimit(quota int64, apiKey, bucketName, cosEndpoi BucketPatch: bucketPatch, } + log.Info(fmt.Sprintf("[%s] Updating bucket quota", reqID), + zap.String("bucket", bucketName), zap.Int64("quota", quota)) _, err = service.UpdateBucketConfig(options) if err != nil { - return fmt.Errorf("failed to update quota for bucket %s to %d bytes: %w", bucketName, quota, err) + log.Error(fmt.Sprintf("[%s] Failed to update quota", reqID), + zap.String("bucket", bucketName), zap.Int64("quota", quota), zap.Error(err)) + return fmt.Errorf("[%s] failed to update quota for bucket %s to %d bytes: %w", reqID, bucketName, quota, err) } + log.Info(fmt.Sprintf("[%s] UpdateQuotaLimit completed successfully", reqID), + zap.String("bucket", bucketName), zap.Int64("quota", quota)) return nil } From 29f5a9797ddc81b1651ecfe8423c432269fca322 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 20 May 2026 19:03:44 +0530 Subject: [PATCH 04/64] replace klogs with zap logs --- cmd/main.go | 6 ++--- pkg/driver/controllerserver.go | 10 ++++---- pkg/driver/identityserver.go | 24 +++++++++++++------ pkg/driver/s3-driver.go | 2 +- pkg/driver/server.go | 23 ++++++++++-------- pkg/mounter/fake_mounter-s3fs.go | 12 +++++++--- pkg/mounter/mounter-rclone.go | 40 ++++++++++++++++++-------------- pkg/mounter/mounter-s3fs.go | 30 ++++++++++++++---------- pkg/utils/driver_utils.go | 36 ++++++++++++++-------------- tests/sanity/sanity_test.go | 21 ++++++++++------- 10 files changed, 121 insertions(+), 83 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index f62ac513..39219784 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -92,13 +92,13 @@ func getConfigBool(envKey string, defaultConf bool, logger zap.Logger) bool { func main() { klog.InitFlags(nil) - defer klog.Flush() - logger := getZapLogger() + defer logger.Sync() // #nosec G104: Best effort sync + loggerLevel := zap.NewAtomicLevel() options := getOptions() - klog.V(1).Info("Starting Server...") + logger.Info("Starting Server...") debugTrace := getConfigBool("DEBUG_TRACE", false, *logger) if debugTrace { diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index 2bc18f05..d9dff063 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -150,7 +150,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) } - secretMapCustom := parseCustomSecret(secret) + secretMapCustom := parseCustomSecret(secret, log) log.Info("Custom secret parsed successfully", zap.Int("secret_param_count", len(secretMapCustom))) if objectPath, exists := secretMapCustom["objectPath"]; exists { @@ -645,7 +645,7 @@ func (cs *controllerServer) ControllerModifyVolume(ctx context.Context, req *csi } func getObjectStorageCredentialsFromSecret(secretMap map[string]string, iamEP string) (*s3client.ObjectStorageCredentials, error) { - klog.Infof("- getObjectStorageCredentialsFromSecret-") + log.Info("Getting object storage credentials from secret") var ( accessKey string secretKey string @@ -688,8 +688,8 @@ func getObjectStorageCredentialsFromSecret(secretMap map[string]string, iamEP st }, nil } -func parseCustomSecret(secret *v1.Secret) map[string]string { - klog.Infof("-parseCustomSecret-") +func parseCustomSecret(secret *v1.Secret, log *zap.Logger) map[string]string { + log.Info("Parsing custom secret") secretMapCustom := make(map[string]string) var ( @@ -777,7 +777,7 @@ func parseCustomSecret(secret *v1.Secret) map[string]string { } func getTempBucketName(mounterType, volumeID string) string { - klog.Infof("mounterType: %v", mounterType) + log.Info("Getting temp bucket name", zap.String("mounter_type", mounterType)) currentTime := time.Now() timestamp := currentTime.Format("20060102150405") diff --git a/pkg/driver/identityserver.go b/pkg/driver/identityserver.go index 64c90fcb..56328a76 100644 --- a/pkg/driver/identityserver.go +++ b/pkg/driver/identityserver.go @@ -13,10 +13,11 @@ package driver import ( "context" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" csi "github.com/container-storage-interface/spec/lib/go/csi" + "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "k8s.io/klog/v2" ) // Implements Identity Sever csi.IdentityServe @@ -25,8 +26,11 @@ type identityServer struct { csi.UnimplementedIdentityServer } -func (csiIdentity *identityServer) GetPluginInfo(_ context.Context, req *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) { - klog.V(3).Infof("identityServer-GetPluginInfo: Request: %+v", req) +func (csiIdentity *identityServer) GetPluginInfo(ctx context.Context, req *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) { + reqID := requestid.FromContext(ctx) + log := csiIdentity.logger.With(zap.String("request_id", reqID)) + + log.Debug("identityServer-GetPluginInfo", zap.Any("request", req)) if csiIdentity.S3Driver == nil { return nil, status.Error(codes.InvalidArgument, "Driver not configured") } @@ -37,8 +41,11 @@ func (csiIdentity *identityServer) GetPluginInfo(_ context.Context, req *csi.Get }, nil } -func (csiIdentity *identityServer) GetPluginCapabilities(_ context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) { - klog.V(3).Infof("identityServer-GetPluginCapabilities: Request %+v", req) +func (csiIdentity *identityServer) GetPluginCapabilities(ctx context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) { + reqID := requestid.FromContext(ctx) + log := csiIdentity.logger.With(zap.String("request_id", reqID)) + + log.Debug("identityServer-GetPluginCapabilities", zap.Any("request", req)) return &csi.GetPluginCapabilitiesResponse{ Capabilities: []*csi.PluginCapability{ { @@ -66,7 +73,10 @@ func (csiIdentity *identityServer) GetPluginCapabilities(_ context.Context, req }, nil } -func (csiIdentity *identityServer) Probe(_ context.Context, req *csi.ProbeRequest) (*csi.ProbeResponse, error) { - klog.V(3).Infof("identityServer-Probe: Request %+v", req) +func (csiIdentity *identityServer) Probe(ctx context.Context, req *csi.ProbeRequest) (*csi.ProbeResponse, error) { + reqID := requestid.FromContext(ctx) + log := csiIdentity.logger.With(zap.String("request_id", reqID)) + + log.Debug("identityServer-Probe", zap.Any("request", req)) return &csi.ProbeResponse{}, nil } diff --git a/pkg/driver/s3-driver.go b/pkg/driver/s3-driver.go index 69ff3d0b..fea1c4bb 100644 --- a/pkg/driver/s3-driver.go +++ b/pkg/driver/s3-driver.go @@ -183,7 +183,7 @@ func (driver *S3Driver) NewS3CosDriver(nodeID string, endpoint string, s3cosSess if err != nil { return nil, err } - klog.Infof("iam endpoint: %v", iamEP) + driver.logger.Info("IAM endpoint", zap.String("iam_endpoint", iamEP)) driver.iamEndpoint = iamEP driver.endpoint = endpoint diff --git a/pkg/driver/server.go b/pkg/driver/server.go index f2081112..bc953017 100644 --- a/pkg/driver/server.go +++ b/pkg/driver/server.go @@ -19,10 +19,10 @@ import ( "sync" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/container-storage-interface/spec/lib/go/csi" "go.uber.org/zap" "google.golang.org/grpc" - "k8s.io/klog/v2" ) // NonBlockingGRPCServer Defines Non blocking GRPC server interfaces @@ -79,7 +79,7 @@ func (s *nonBlockingGRPCServer) Setup(endpoint string, ids csi.IdentityServer, c opts := []grpc.ServerOption{ grpc.ChainUnaryInterceptor( UnaryServerInterceptor(s.logger), // Request ID interceptor - logGRPC, // Legacy logging interceptor + s.logGRPC, // Logging interceptor ), } @@ -133,13 +133,13 @@ func (s *nonBlockingGRPCServer) Setup(endpoint string, ids csi.IdentityServer, c switch s.mode { case "controller": - klog.V(3).Info("--Starting server in controller mode--") + s.logger.Debug("Starting server in controller mode") csi.RegisterControllerServer(s.server, cs) case "node": - klog.V(3).Info("--Starting server in node server mode--") + s.logger.Debug("Starting server in node server mode") csi.RegisterNodeServer(s.server, ns) case "controller-node": - klog.V(3).Info("--Starting node and controller server mode--") + s.logger.Debug("Starting node and controller server mode") csi.RegisterControllerServer(s.server, cs) csi.RegisterNodeServer(s.server, ns) } @@ -161,14 +161,17 @@ func (s *nonBlockingGRPCServer) serve(endpoint string, ids csi.IdentityServer, c } } -// logGRPC ... -func logGRPC(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - klog.V(3).Infof("GRPC call: %s", info.FullMethod) +// logGRPC logs GRPC calls with request ID context +func (s *nonBlockingGRPCServer) logGRPC(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + reqID := requestid.FromContext(ctx) + log := s.logger.With(zap.String("request_id", reqID)) + + log.Debug("GRPC call", zap.String("method", info.FullMethod)) resp, err := handler(ctx, req) if err != nil { - klog.Errorf("GRPC error: %v", err) + log.Error("GRPC error", zap.Error(err), zap.String("method", info.FullMethod)) } else { - klog.V(5).Infof("GRPC response: %+v", resp) + log.Debug("GRPC response", zap.Any("response", resp), zap.String("method", info.FullMethod)) } return resp, err } diff --git a/pkg/mounter/fake_mounter-s3fs.go b/pkg/mounter/fake_mounter-s3fs.go index 88532534..a7fa3b4c 100644 --- a/pkg/mounter/fake_mounter-s3fs.go +++ b/pkg/mounter/fake_mounter-s3fs.go @@ -1,6 +1,12 @@ +//go:build linux +// +build linux + package mounter -import "errors" +import ( + "context" + "errors" +) type fakes3fsMounter struct { bucketName string @@ -29,14 +35,14 @@ func fakenewS3fsMounter(isFailedMount, isFailedUnmount bool) Mounter { } } -func (s3fs *fakes3fsMounter) Mount(source string, target string) error { +func (s3fs *fakes3fsMounter) Mount(ctx context.Context, source string, target string) error { if s3fs.isFailedMount { return errors.New("failed to mount s3fs") } return nil } -func (s3fs *fakes3fsMounter) Unmount(target string) error { +func (s3fs *fakes3fsMounter) Unmount(ctx context.Context, target string) error { if s3fs.isFailedUnmount { return errors.New("failed to unmount s3fs") } diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index cfc8f0a7..31cb090e 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + /******************************************************************************* * IBM Confidential * OCO Source Materials @@ -57,6 +60,7 @@ const ( var ( createConfigWrap = createConfig removeConfigFile = removeRcloneConfigFile + rcloneLogger, _ = zap.NewProduction() ) func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { @@ -143,7 +147,7 @@ func updateMountOptions(dafaultMountOptions []string, secretMap map[string]strin stringData, ok := secretMap["mountOptions"] if !ok { - klog.Infof("No new mountOptions found. Using default mountOptions: %v", dafaultMountOptions) + rcloneLogger.Info("No new mountOptions found. Using default mountOptions", zap.Any("default_mount_options", dafaultMountOptions)) return dafaultMountOptions } @@ -156,7 +160,7 @@ func updateMountOptions(dafaultMountOptions []string, secretMap map[string]strin } opts := strings.Split(line, "=") if len(opts) != 2 { - klog.Infof("Invalid mount option: %s\n", line) + rcloneLogger.Info("Invalid mount option", zap.String("line", line)) continue } mountOptsMap[strings.TrimSpace(opts[0])] = strings.TrimSpace(opts[1]) @@ -169,14 +173,15 @@ func updateMountOptions(dafaultMountOptions []string, secretMap map[string]strin updatedOptions = append(updatedOptions, option) } - klog.Infof("Updated rclone Options: %v", updatedOptions) + rcloneLogger.Info("Updated rclone Options", zap.Any("updated_options", updatedOptions)) return updatedOptions } func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target string) error { reqID := requestid.FromContext(ctx) - log := logger.WithRequestID(ctx) + baseLogger, _ := zap.NewProduction() + log := logger.WithRequestID(ctx, baseLogger) log.Info(fmt.Sprintf("[%s] RcloneMounter Mount started", reqID), zap.String("source", source), zap.String("target", target)) @@ -245,7 +250,8 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { reqID := requestid.FromContext(ctx) - log := logger.WithRequestID(ctx) + baseLogger, _ := zap.NewProduction() + log := logger.WithRequestID(ctx, baseLogger) log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount started", reqID), zap.String("target", target)) @@ -322,34 +328,34 @@ func createConfig(configPathWithVolID string, rclone *RcloneMounter) error { if err := MakeDir(configPathWithVolID, 0755); // #nosec G301: used for rclone err != nil { - klog.Errorf("RcloneMounter Mount: Cannot create directory %s: %v", configPathWithVolID, err) + rcloneLogger.Error("RcloneMounter Mount: Cannot create directory", zap.String("path", configPathWithVolID), zap.Error(err)) return err } configFile := path.Join(configPathWithVolID, configFileName) file, err := CreateFile(configFile) // #nosec G304 used for rclone if err != nil { - klog.Errorf("RcloneMounter Mount: Cannot create file %s: %v", configFileName, err) + rcloneLogger.Error("RcloneMounter Mount: Cannot create file", zap.String("file", configFileName), zap.Error(err)) return err } defer func() { if err = file.Close(); err != nil { - klog.Errorf("RcloneMounter Mount: Cannot close file %s: %v", configFileName, err) + rcloneLogger.Error("RcloneMounter Mount: Cannot close file", zap.String("file", configFileName), zap.Error(err)) } }() err = Chmod(configFile, 0644) // #nosec G302: used for rclone if err != nil { - klog.Errorf("RcloneMounter Mount: Cannot change permissions on file %s: %v", configFileName, err) + rcloneLogger.Error("RcloneMounter Mount: Cannot change permissions on file", zap.String("file", configFileName), zap.Error(err)) return err } - klog.Info("-Rclone writing to config-") + rcloneLogger.Info("Rclone writing to config") datawriter := bufio.NewWriter(file) for _, line := range configParams { _, err = datawriter.WriteString(line + "\n") if err != nil { - klog.Errorf("RcloneMounter Mount: Could not write to config file: %v", err) + rcloneLogger.Error("RcloneMounter Mount: Could not write to config file", zap.Error(err)) return err } } @@ -357,7 +363,7 @@ func createConfig(configPathWithVolID string, rclone *RcloneMounter) error { if err != nil { return err } - klog.Info("-Rclone created rclone config file-") + rcloneLogger.Info("Rclone created rclone config file") return nil } @@ -403,21 +409,21 @@ func removeRcloneConfigFile(configPath, target string) { _, err := Stat(configPathWithVolID) if err != nil { if os.IsNotExist(err) { - klog.Infof("removeRcloneConfigFile: Config file directory does not exist: %s", configPathWithVolID) + rcloneLogger.Info("removeRcloneConfigFile: Config file directory does not exist", zap.String("path", configPathWithVolID)) return } - klog.Errorf("removeRcloneConfigFile: Attempt %d - Failed to stat path %s: %v", retry, configPathWithVolID, err) + rcloneLogger.Error("removeRcloneConfigFile: Failed to stat path", zap.Int("attempt", retry), zap.String("path", configPathWithVolID), zap.Error(err)) time.Sleep(constants.Interval) continue } err = RemoveAll(configPathWithVolID) if err != nil { - klog.Errorf("removeRcloneConfigFile: Attempt %d - Failed to remove config file path %s: %v", retry, configPathWithVolID, err) + rcloneLogger.Error("removeRcloneConfigFile: Failed to remove config file path", zap.Int("attempt", retry), zap.String("path", configPathWithVolID), zap.Error(err)) time.Sleep(constants.Interval) continue } - klog.Infof("removeRcloneConfigFile: Successfully removed config file path: %s", configPathWithVolID) + rcloneLogger.Info("removeRcloneConfigFile: Successfully removed config file path", zap.String("path", configPathWithVolID)) return } - klog.Errorf("removeRcloneConfigFile: Failed to remove config file path after %d attempts", maxRetries) + rcloneLogger.Error("removeRcloneConfigFile: Failed to remove config file path after max attempts", zap.Int("max_attempts", maxRetries)) } diff --git a/pkg/mounter/mounter-s3fs.go b/pkg/mounter/mounter-s3fs.go index d66dc09d..dd481634 100644 --- a/pkg/mounter/mounter-s3fs.go +++ b/pkg/mounter/mounter-s3fs.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + /******************************************************************************* * IBM Confidential * OCO Source Materials @@ -49,8 +52,9 @@ const ( ) var ( - writePassWrap = writePass - removeFile = removeS3FSCredFile + writePassWrap = writePass + removeFile = removeS3FSCredFile + s3fsLogger, _ = zap.NewProduction() ) func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils, defaultParams map[string]string) Mounter { @@ -111,7 +115,8 @@ func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterU func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string) error { reqID := requestid.FromContext(ctx) - log := logger.WithRequestID(ctx) + baseLogger, _ := zap.NewProduction() + log := logger.WithRequestID(ctx, baseLogger) log.Info(fmt.Sprintf("[%s] S3FSMounter Mount started", reqID), zap.String("source", source), zap.String("target", target)) @@ -198,7 +203,8 @@ func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string func (s3fs *S3fsMounter) Unmount(ctx context.Context, target string) error { reqID := requestid.FromContext(ctx) - log := logger.WithRequestID(ctx) + baseLogger, _ := zap.NewProduction() + log := logger.WithRequestID(ctx, baseLogger) log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount started", reqID), zap.String("target", target)) @@ -267,7 +273,7 @@ func updateS3FSMountOptions(defaultMountOp []string, secretMap map[string]string stringData, ok := secretMap["mountOptions"] if !ok { - klog.Infof("No new mountOptions found. Using default mountOptions: %v", mountOptsMap) + s3fsLogger.Info("No new mountOptions found. Using default mountOptions", zap.Any("default_mount_options", mountOptsMap)) } else { lines := strings.Split(stringData, "\n") // Update map @@ -281,7 +287,7 @@ func updateS3FSMountOptions(defaultMountOp []string, secretMap map[string]string } else if len(opts) == 1 { mountOptsMap[strings.TrimSpace(opts[0])] = strings.TrimSpace(opts[0]) } else { - klog.Infof("Invalid mount option: %s\n", line) + s3fsLogger.Info("Invalid mount option", zap.String("line", line)) } } } @@ -318,7 +324,7 @@ func updateS3FSMountOptions(defaultMountOp []string, secretMap map[string]string } } - klog.Infof("updated S3fsMounter Options: %v", updatedOptions) + s3fsLogger.Info("updated S3fsMounter Options", zap.Any("updated_options", updatedOptions)) return updatedOptions } @@ -380,21 +386,21 @@ func removeS3FSCredFile(credDir, target string) { _, err := Stat(metaPath) if err != nil { if os.IsNotExist(err) { - klog.Infof("removeS3FSCredFile: Password file directory does not exist: %s", metaPath) + s3fsLogger.Info("removeS3FSCredFile: Password file directory does not exist", zap.String("path", metaPath)) return } - klog.Errorf("removeS3FSCredFile: Attempt %d - Failed to stat path %s: %v", retry, metaPath, err) + s3fsLogger.Error("removeS3FSCredFile: Failed to stat path", zap.Int("attempt", retry), zap.String("path", metaPath), zap.Error(err)) time.Sleep(constants.Interval) continue } err = RemoveAll(metaPath) if err != nil { - klog.Errorf("removeS3FSCredFile: Attempt %d - Failed to remove password file path %s: %v", retry, metaPath, err) + s3fsLogger.Error("removeS3FSCredFile: Failed to remove password file path", zap.Int("attempt", retry), zap.String("path", metaPath), zap.Error(err)) time.Sleep(constants.Interval) continue } - klog.Infof("removeS3FSCredFile: Successfully removed password file path: %s", metaPath) + s3fsLogger.Info("removeS3FSCredFile: Successfully removed password file path", zap.String("path", metaPath)) return } - klog.Errorf("removeS3FSCredFile: Failed to remove password file after %d attempts", maxRetries) + s3fsLogger.Error("removeS3FSCredFile: Failed to remove password file after max attempts", zap.Int("max_attempts", maxRetries)) } diff --git a/pkg/utils/driver_utils.go b/pkg/utils/driver_utils.go index d88568d5..d14eb187 100644 --- a/pkg/utils/driver_utils.go +++ b/pkg/utils/driver_utils.go @@ -12,16 +12,18 @@ import ( rc "github.com/IBM/ibm-cos-sdk-go-config/v2/resourceconfigurationv1" "github.com/IBM/ibm-object-csi-driver/pkg/constants" "github.com/container-storage-interface/spec/lib/go/csi" + "go.uber.org/zap" "google.golang.org/protobuf/proto" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "k8s.io/klog/v2" "k8s.io/kubernetes/pkg/volume/util/fs" ) +var utilLogger, _ = zap.NewProduction() + type StatsUtils interface { BucketToDelete(volumeID string) (string, error) FSInfo(path string) (int64, int64, int64, int64, int64, int64, error) @@ -93,17 +95,17 @@ func (su *DriverStatsUtils) BucketToDelete(volumeID string) (string, error) { pv, err := clientset.CoreV1().PersistentVolumes().Get(context.Background(), volumeID, metav1.GetOptions{}) if err != nil { - klog.Errorf("Unable to fetch bucket %v", err) + utilLogger.Error("Unable to fetch bucket", zap.Error(err)) return "", err } - klog.Infof("***Attributes: %v", pv.Spec.CSI.VolumeAttributes) + utilLogger.Info("Volume attributes", zap.Any("attributes", pv.Spec.CSI.VolumeAttributes)) if pv.Spec.CSI.VolumeAttributes["userProvidedBucket"] != "true" { - klog.Infof("Bucket will be deleted %v", pv.Spec.CSI.VolumeAttributes["bucketName"]) + utilLogger.Info("Bucket will be deleted", zap.String("bucket_name", pv.Spec.CSI.VolumeAttributes["bucketName"])) return pv.Spec.CSI.VolumeAttributes["bucketName"], nil } - klog.Infof("Bucket will be persisted %v", pv.Spec.CSI.VolumeAttributes["bucketName"]) + utilLogger.Info("Bucket will be persisted", zap.String("bucket_name", pv.Spec.CSI.VolumeAttributes["bucketName"])) return "", nil } @@ -115,10 +117,10 @@ func (su *DriverStatsUtils) CheckMount(targetPath string) error { out, err := exec.Command("mountpoint", targetPath).CombinedOutput() outStr := strings.TrimSpace(string(out)) if err != nil { - klog.V(3).Infof("Check if mountPath exists: Output string- %+v", outStr) + utilLogger.Debug("Check if mountPath exists", zap.String("output", outStr)) if strings.HasSuffix(outStr, "No such file or directory") { if err = os.MkdirAll(targetPath, 0750); err != nil { - klog.V(2).Infof("checkMount: Error: %+v", err) + utilLogger.Debug("checkMount: Error", zap.Error(err)) return err } } else { @@ -161,7 +163,7 @@ func (su *DriverStatsUtils) GetBucketUsage(volumeID string) (int64, error) { } resourceConfig, err := rc.NewResourceConfigurationV1(rcOptions) if err != nil { - klog.Error("Failed to create resource config") + utilLogger.Error("Failed to create resource config") return 0, err } @@ -171,7 +173,7 @@ func (su *DriverStatsUtils) GetBucketUsage(volumeID string) (int64, error) { res, _, err := resourceConfig.GetBucketConfig(bucketOptions) if err != nil { - klog.Error("Failed to get bucket config") + utilLogger.Error("Failed to get bucket config") return 0, err } @@ -205,7 +207,7 @@ func (su *DriverStatsUtils) GetPVC(pvcName, pvcNamespace string) (*v1.Persistent pvc, err := k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Get(context.TODO(), pvcName, metav1.GetOptions{}) if err != nil { - klog.Errorf("Unable to fetch pvc %v", err) + utilLogger.Error("Unable to fetch pvc", zap.Error(err)) return nil, fmt.Errorf("error getting PVC: %v", err) } @@ -234,7 +236,7 @@ func (su *DriverStatsUtils) GetPV(volumeID string) (*v1.PersistentVolume, error) pv, err := k8sClient.CoreV1().PersistentVolumes().Get(context.Background(), volumeID, metav1.GetOptions{}) if err != nil { - klog.Errorf("Unable to fetch pv %v", err) + utilLogger.Error("Unable to fetch pv", zap.Error(err)) return nil, fmt.Errorf("error getting PV: %v", err) } @@ -315,14 +317,14 @@ func CreateK8sClient() (*kubernetes.Clientset, error) { // Create a Kubernetes client configuration config, err := rest.InClusterConfig() if err != nil { - klog.Error("Error creating Kubernetes client configuration: ", err) + utilLogger.Error("Error creating Kubernetes client configuration", zap.Error(err)) return nil, err } // Create a Kubernetes clientset clientset, err := kubernetes.NewForConfig(config) if err != nil { - klog.Error("Error creating Kubernetes clientset: ", err) + utilLogger.Error("Error creating Kubernetes clientset", zap.Error(err)) return nil, err } @@ -348,7 +350,7 @@ func getClusterType() (string, error) { } clusterType := clusterConfig["cluster_type"] - klog.Info("Cluster Type ", clusterType) + utilLogger.Info("Cluster Type", zap.String("cluster_type", clusterType)) return clusterType, nil } @@ -357,7 +359,7 @@ func fetchSecretUsingPV(volumeID string, su *DriverStatsUtils) (*v1.Secret, erro if err != nil { return nil, err } - klog.Info("secret fetched from PV:\n\t", pv.Spec.CSI.NodePublishSecretRef) + utilLogger.Info("Secret fetched from PV", zap.String("secret_name", pv.Spec.CSI.NodePublishSecretRef.Name), zap.String("secret_namespace", pv.Spec.CSI.NodePublishSecretRef.Namespace)) secretName := pv.Spec.CSI.NodePublishSecretRef.Name secretNamespace := pv.Spec.CSI.NodePublishSecretRef.Namespace @@ -367,7 +369,7 @@ func fetchSecretUsingPV(volumeID string, su *DriverStatsUtils) (*v1.Secret, erro } if secretNamespace == "" { - klog.Info("secret Namespace not found. trying to fetch the secret in default namespace") + utilLogger.Info("Secret namespace not found, trying to fetch the secret in default namespace") secretNamespace = constants.DefaultNamespace } @@ -380,7 +382,7 @@ func fetchSecretUsingPV(volumeID string, su *DriverStatsUtils) (*v1.Secret, erro return nil, fmt.Errorf("secret not found with name: %v", secretNamespace) } - klog.Info("secret details found. secretName: ", secret.Name) + utilLogger.Info("Secret details found", zap.String("secret_name", secret.Name)) return secret, nil } diff --git a/tests/sanity/sanity_test.go b/tests/sanity/sanity_test.go index bda70478..62c7c6a8 100644 --- a/tests/sanity/sanity_test.go +++ b/tests/sanity/sanity_test.go @@ -34,7 +34,6 @@ import ( "google.golang.org/grpc/status" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/klog/v2" ) var ( @@ -177,26 +176,32 @@ func (s *fakeObjectStorageSession) UpdateQuotaLimit(quota int64, apiKey, bucketN } // Fake NewMounterFactory -type FakeS3fsMounterFactory struct{} +type FakeS3fsMounterFactory struct { + logger *zap.Logger +} func FakeNewS3fsMounterFactory() *FakeS3fsMounterFactory { - return &FakeS3fsMounterFactory{} + // Create a no-op logger for tests + logger, _ := zap.NewDevelopment() + return &FakeS3fsMounterFactory{logger: logger} } -type Fakes3fsMounter struct{} +type Fakes3fsMounter struct { + logger *zap.Logger +} func (s *FakeS3fsMounterFactory) NewMounter(attrib map[string]string, secretMap map[string]string, mountFlags []string, defaultMOMap map[string]string) mounter.Mounter { - klog.Info("-New S3FS Fake Mounter-") - return &Fakes3fsMounter{} + s.logger.Info("New S3FS Fake Mounter") + return &Fakes3fsMounter{logger: s.logger} } func (s3fs *Fakes3fsMounter) Mount(source string, target string) error { - klog.Info("-S3FSMounter Mount-") + s3fs.logger.Info("S3FSMounter Mount", zap.String("source", source), zap.String("target", target)) return nil } func (s3fs *Fakes3fsMounter) Unmount(target string) error { - klog.Info("-S3FSMounter Unmount-") + s3fs.logger.Info("S3FSMounter Unmount", zap.String("target", target)) return nil } From 6f9a008bf6173e24054fd0dbe45d4971bfc92c7c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 26 May 2026 11:34:11 +0530 Subject: [PATCH 05/64] migrate from klog to zap log --- cmd/main.go | 2 - pkg/driver/controllerserver.go | 269 +++++++++++++++------------------ pkg/driver/nodeserver.go | 17 +-- pkg/driver/s3-driver.go | 1 - 4 files changed, 133 insertions(+), 156 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 39219784..20ea17ba 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -31,7 +31,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/zap" "go.uber.org/zap/zapcore" - "k8s.io/klog/v2" ) // Options is the combined set of options for all operating modes. @@ -91,7 +90,6 @@ func getConfigBool(envKey string, defaultConf bool, logger zap.Logger) bool { } func main() { - klog.InitFlags(nil) logger := getZapLogger() defer logger.Sync() // #nosec G104: Best effort sync diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index d9dff063..64e3317b 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -32,7 +32,6 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" v1 "k8s.io/api/core/v1" - "k8s.io/klog/v2" ) // Implements Controller csi.ControllerServer @@ -47,7 +46,6 @@ type controllerServer struct { func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { // Extract request ID from context (added by interceptor) reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) var ( bucketName string @@ -60,14 +58,14 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol quotaLimitEnabled bool ) - log.Info("CreateVolume started", zap.String("volume_name", req.GetName())) + logger.Info(ctx, cs.Logger, "CreateVolume started", zap.String("volume_name", req.GetName())) modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { logger.Error(ctx, cs.Logger, "Error modifying request", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) } - log.Debug("CreateVolume request details", zap.Any("request", modifiedRequest.(*csi.CreateVolumeRequest))) + logger.Debug(ctx, cs.Logger, "CreateVolume request details", zap.Any("request", modifiedRequest.(*csi.CreateVolumeRequest))) volumeName, err := sanitizeVolumeID(req.GetName()) if err != nil { @@ -79,7 +77,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol logger.Error(ctx, cs.Logger, "Volume name missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume name missing in request", reqID)) } - log.Info("Processing volume creation", zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "Processing volume creation", zap.String("volume_id", volumeID)) caps := req.GetVolumeCapabilities() if caps == nil { @@ -87,7 +85,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume Capabilities missing in request", reqID)) } for _, cap := range caps { - log.Debug("Volume capability", zap.String("capability", cap.String())) + logger.Debug(ctx, cs.Logger, "Volume capability", zap.String("capability", cap.String())) if cap.GetBlock() != nil { logger.Error(ctx, cs.Logger, "Block volume not supported") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume type block Volume not supported", reqID)) @@ -98,14 +96,14 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if params == nil { params = make(map[string]string) } - log.Info("CreateVolume parameters received", zap.Int("param_count", len(params))) + logger.Info(ctx, cs.Logger, "CreateVolume parameters received", zap.Int("param_count", len(params))) secretMap := req.GetSecrets() - log.Info("Secrets received", zap.Int("secret_count", len(secretMap))) + logger.Info(ctx, cs.Logger, "Secrets received", zap.Int("secret_count", len(secretMap))) var customSecretName string if len(secretMap) == 0 { - log.Info("No secret in request, fetching custom secret from PVC annotations") + logger.Info(ctx, cs.Logger, "No secret in request, fetching custom secret from PVC annotations") pvcName = params[constants.PVCNameKey] pvcNamespace = params[constants.PVCNamespaceKey] @@ -119,14 +117,14 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol pvcNamespace = constants.DefaultNamespace } - log.Info("Fetching PVC", zap.String("pvc_name", pvcName), zap.String("namespace", pvcNamespace)) + logger.Info(ctx, cs.Logger, "Fetching PVC", zap.String("pvc_name", pvcName), zap.String("namespace", pvcNamespace)) pvcRes, err := cs.Stats.GetPVC(pvcName, pvcNamespace) if err != nil { logger.Error(ctx, cs.Logger, "PVC resource not found", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] PVC resource not found %v", reqID, err)) } - log.Debug("PVC annotations", zap.Any("annotations", pvcRes.Annotations)) + logger.Debug(ctx, cs.Logger, "PVC annotations", zap.Any("annotations", pvcRes.Annotations)) pvcAnnotations := pvcRes.Annotations @@ -139,52 +137,52 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } if secretNamespace == "" { - log.Warn("Secret namespace not specified in PVC annotations, using default namespace") + logger.Warn(ctx, cs.Logger, "Secret namespace not specified in PVC annotations, using default namespace") secretNamespace = constants.DefaultNamespace } - log.Info("Fetching secret", zap.String("secret_name", customSecretName), zap.String("namespace", secretNamespace)) + logger.Info(ctx, cs.Logger, "Fetching secret", zap.String("secret_name", customSecretName), zap.String("namespace", secretNamespace)) secret, err := cs.Stats.GetSecret(customSecretName, secretNamespace) if err != nil { logger.Error(ctx, cs.Logger, "Secret resource not found", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) } - secretMapCustom := parseCustomSecret(secret, log) - log.Info("Custom secret parsed successfully", zap.Int("secret_param_count", len(secretMapCustom))) + secretMapCustom := parseCustomSecret(ctx, secret, cs.Logger) + logger.Info(ctx, cs.Logger, "Custom secret parsed successfully", zap.Int("secret_param_count", len(secretMapCustom))) if objectPath, exists := secretMapCustom["objectPath"]; exists { - log.Info("ObjectPath found in secret", zap.String("volume_id", volumeID), zap.String("object_path", objectPath)) + logger.Info(ctx, cs.Logger, "ObjectPath found in secret", zap.String("volume_id", volumeID), zap.String("object_path", objectPath)) params["objectPath"] = objectPath } else { - log.Info("No objectPath in secret, mounting bucket root", zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "No objectPath in secret, mounting bucket root", zap.String("volume_id", volumeID)) } secretMap = secretMapCustom } if quotaLimitStr, ok := secretMap[constants.QuotaLimitKey]; ok && quotaLimitStr != "" { - log.Info(fmt.Sprintf("[%s] Quota limit parameter found", reqID), zap.String("quota_limit", quotaLimitStr)) + logger.Info(ctx, cs.Logger, "Quota limit parameter found", zap.String("quota_limit", quotaLimitStr)) quotaLimitEnabled, err = strconv.ParseBool(quotaLimitStr) if err != nil { - log.Error(fmt.Sprintf("[%s] Invalid quota limit value", reqID), zap.String("value", quotaLimitStr), zap.Error(err)) + logger.Error(ctx, cs.Logger, "Invalid quota limit value", zap.String("value", quotaLimitStr), zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] invalid quotaLimit value %q: must be 'true' or 'false'", reqID, quotaLimitStr)) } if quotaLimitEnabled { if secretMap[constants.ResourceConfigApiKey] == "" { - log.Error(fmt.Sprintf("[%s] Resource config API key missing for quota limit", reqID)) + logger.Error(ctx, cs.Logger, "Resource config API key missing for quota limit") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] resourceConfigApiKey missing in secret, cannot set quota limit for bucket", reqID)) } quotaBytes := req.GetCapacityRange().GetRequiredBytes() if quotaBytes <= 0 { - log.Error(fmt.Sprintf("[%s] Invalid storage size for quota limit", reqID), zap.Int64("bytes", quotaBytes)) + logger.Error(ctx, cs.Logger, "Invalid storage size for quota limit", zap.Int64("bytes", quotaBytes)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] enable quotaLimit requested but no positive storage size requested in PVC", reqID)) } - log.Info(fmt.Sprintf("[%s] Quota limit enabled", reqID), zap.Int64("quota_bytes", quotaBytes)) + logger.Info(ctx, cs.Logger, "Quota limit enabled", zap.Int64("quota_bytes", quotaBytes)) } } @@ -195,7 +193,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol params["cosEndpoint"] = endPoint } if endPoint == "" { - log.Error(fmt.Sprintf("[%s] COS endpoint not specified", reqID)) + logger.Error(ctx, cs.Logger, "COS endpoint not specified") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] cosEndpoint unknown", reqID)) } @@ -206,13 +204,13 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol params["locationConstraint"] = locationConstraint } if locationConstraint == "" { - log.Error(fmt.Sprintf("[%s] Location constraint not specified", reqID)) + logger.Error(ctx, cs.Logger, "Location constraint not specified") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] locationConstraint unknown", reqID)) } kpRootKeyCrn = secretMap["kpRootKeyCRN"] if kpRootKeyCrn != "" { - log.Info(fmt.Sprintf("[%s] Key Protect root key CRN provided for bucket encryption", reqID)) + logger.Info(ctx, cs.Logger, "Key Protect root key CRN provided for bucket encryption") } mounter := secretMap["mounter"] @@ -221,7 +219,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } else { params["mounter"] = mounter } - log.Info(fmt.Sprintf("[%s] Mounter type configured", reqID), zap.String("mounter", mounter)) + logger.Info(ctx, cs.Logger, "Mounter type configured", zap.String("mounter", mounter)) bucketName = secretMap["bucketName"] @@ -229,28 +227,28 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if val, ok := secretMap[constants.BucketVersioning]; ok && val != "" { enable := strings.ToLower(strings.TrimSpace(val)) if enable != "true" && enable != "false" { - log.Error(fmt.Sprintf("[%s] Invalid bucket versioning value in secret", reqID), zap.String("value", val)) + logger.Error(ctx, cs.Logger, "Invalid bucket versioning value in secret", zap.String("value", val)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Invalid BucketVersioning value in secret: %s. Value set %s. Must be 'true' or 'false'", reqID, customSecretName, val)) } bucketVersioning = enable - log.Info(fmt.Sprintf("[%s] Bucket versioning from secret", reqID), zap.String("versioning", bucketVersioning)) + logger.Info(ctx, cs.Logger, "Bucket versioning from secret", zap.String("versioning", bucketVersioning)) } else if val, ok := params[constants.BucketVersioning]; ok && val != "" { enable := strings.ToLower(strings.TrimSpace(val)) if enable != "true" && enable != "false" { - log.Error(fmt.Sprintf("[%s] Invalid bucket versioning value in storage class", reqID), zap.String("value", val)) + logger.Error(ctx, cs.Logger, "Invalid bucket versioning value in storage class", zap.String("value", val)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Invalid bucketVersioning value in storage class: %s. Must be 'true' or 'false'", reqID, val)) } bucketVersioning = enable - log.Info(fmt.Sprintf("[%s] Bucket versioning from storage class", reqID), zap.String("versioning", bucketVersioning)) + logger.Info(ctx, cs.Logger, "Bucket versioning from storage class", zap.String("versioning", bucketVersioning)) } - creds, err := getObjectStorageCredentialsFromSecret(secretMap, cs.iamEndpoint) + creds, err := getObjectStorageCredentialsFromSecret(ctx, secretMap, cs.iamEndpoint, cs.Logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Error getting credentials from secret", reqID), zap.Error(err)) + logger.Error(ctx, cs.Logger, "Error getting credentials from secret", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in getting credentials %v", reqID, err)) } - log.Info(fmt.Sprintf("[%s] Creating object storage session", reqID), + logger.Info(ctx, cs.Logger, "Creating object storage session", zap.String("endpoint", endPoint), zap.String("location_constraint", locationConstraint)) sess := cs.cosSession.NewObjectStorageSession(endPoint, locationConstraint, creds, cs.Logger) @@ -258,79 +256,79 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol params["userProvidedBucket"] = "true" if bucketName != "" { // User Provided bucket. Check its existence and create if not present - log.Info(fmt.Sprintf("[%s] Bucket name provided", reqID), zap.String("bucket_name", bucketName)) - log.Info(fmt.Sprintf("[%s] Checking if bucket already exists", reqID), zap.String("bucket_name", bucketName)) + logger.Info(ctx, cs.Logger, "Bucket name provided", zap.String("bucket_name", bucketName)) + logger.Info(ctx, cs.Logger, "Checking if bucket already exists", zap.String("bucket_name", bucketName)) if err := sess.CheckBucketAccess(ctx, bucketName); err != nil { - log.Info(fmt.Sprintf("[%s] Bucket not accessible, creating new bucket", reqID), + logger.Info(ctx, cs.Logger, "Bucket not accessible, creating new bucket", zap.String("bucket_name", bucketName), zap.Error(err)) - err = createBucket(ctx, sess, bucketName, kpRootKeyCrn, log) + err = createBucket(ctx, sess, bucketName, kpRootKeyCrn, cs.Logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to create bucket", reqID), + logger.Error(ctx, cs.Logger, "Failed to create bucket", zap.String("bucket_name", bucketName), zap.Error(err)) return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] %v: %v", reqID, err, bucketName)) } params["userProvidedBucket"] = "false" - log.Info(fmt.Sprintf("[%s] Created bucket successfully", reqID), zap.String("bucket_name", bucketName)) + logger.Info(ctx, cs.Logger, "Created bucket successfully", zap.String("bucket_name", bucketName)) } if quotaLimitEnabled { quotaBytes := req.GetCapacityRange().GetRequiredBytes() resConfApikey := secretMap[constants.ResourceConfigApiKey] - log.Info(fmt.Sprintf("[%s] Applying hard quota to bucket", reqID), + logger.Info(ctx, cs.Logger, "Applying hard quota to bucket", zap.Int64("quota_bytes", quotaBytes), zap.String("bucket_name", bucketName)) err = sess.UpdateQuotaLimit(ctx, quotaBytes, resConfApikey, bucketName, endPoint, creds.IAMEndpoint) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to set quota limit on bucket", reqID), + logger.Error(ctx, cs.Logger, "Failed to set quota limit on bucket", zap.String("bucket_name", bucketName), zap.Error(err)) if params["userProvidedBucket"] == "false" { if delErr := sess.DeleteBucket(ctx, bucketName); delErr != nil { - log.Error(fmt.Sprintf("[%s] Failed to delete bucket after quota limit failure", reqID), + logger.Error(ctx, cs.Logger, "Failed to delete bucket after quota limit failure", zap.String("bucket_name", bucketName), zap.Error(delErr)) } } return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set bucket quota limit: %v", reqID, err)) } - log.Info(fmt.Sprintf("[%s] Successfully applied hard quota to bucket", reqID), + logger.Info(ctx, cs.Logger, "Successfully applied hard quota to bucket", zap.Int64("quota_bytes", quotaBytes), zap.String("bucket_name", bucketName)) } if bucketVersioning != "" { enable := strings.ToLower(strings.TrimSpace(bucketVersioning)) == "true" - log.Info(fmt.Sprintf("[%s] Setting bucket versioning", reqID), + logger.Info(ctx, cs.Logger, "Setting bucket versioning", zap.Bool("enable", enable), zap.String("bucket_name", bucketName)) err := sess.SetBucketVersioning(ctx, bucketName, enable) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to set bucket versioning", reqID), + logger.Error(ctx, cs.Logger, "Failed to set bucket versioning", zap.Bool("enable", enable), zap.String("bucket_name", bucketName), zap.Error(err)) if params["userProvidedBucket"] == "false" { err1 := sess.DeleteBucket(ctx, bucketName) if err1 != nil { - log.Error(fmt.Sprintf("[%s] Failed to delete bucket after versioning failure", reqID), + logger.Error(ctx, cs.Logger, "Failed to delete bucket after versioning failure", zap.String("bucket_name", bucketName), zap.Error(err1)) return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] cannot set versioning: %v and cannot delete bucket %s: %v", reqID, err, bucketName, err1)) } } return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set versioning %t for bucket %s: %v", reqID, enable, bucketName, err)) } - log.Info(fmt.Sprintf("[%s] Bucket versioning set successfully", reqID), + logger.Info(ctx, cs.Logger, "Bucket versioning set successfully", zap.Bool("enable", enable), zap.String("bucket_name", bucketName)) } params["bucketName"] = bucketName } else { // Generate random temp bucket name based on volume id - log.Info(fmt.Sprintf("[%s] Bucket name not provided, generating temp bucket", reqID)) - tempBucketName := getTempBucketName(mounter, volumeID) + logger.Info(ctx, cs.Logger, "Bucket name not provided, generating temp bucket") + tempBucketName := getTempBucketName(ctx, mounter, volumeID, cs.Logger) if tempBucketName == "" { - log.Error(fmt.Sprintf("[%s] Unable to generate temp bucket name", reqID)) + logger.Error(ctx, cs.Logger, "Unable to generate temp bucket name") return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] Unable to access the bucket: %v", reqID, tempBucketName)) } - log.Info(fmt.Sprintf("[%s] Creating temp bucket", reqID), zap.String("temp_bucket_name", tempBucketName)) - err = createBucket(ctx, sess, tempBucketName, kpRootKeyCrn, log) + logger.Info(ctx, cs.Logger, "Creating temp bucket", zap.String("temp_bucket_name", tempBucketName)) + err = createBucket(ctx, sess, tempBucketName, kpRootKeyCrn, cs.Logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to create temp bucket", reqID), + logger.Error(ctx, cs.Logger, "Failed to create temp bucket", zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] %v: %v", reqID, err, tempBucketName)) } @@ -339,48 +337,48 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol quotaBytes := req.GetCapacityRange().GetRequiredBytes() resConfApikey := secretMap[constants.ResourceConfigApiKey] - log.Info(fmt.Sprintf("[%s] Applying hard quota to temp bucket", reqID), + logger.Info(ctx, cs.Logger, "Applying hard quota to temp bucket", zap.Int64("quota_bytes", quotaBytes), zap.String("temp_bucket_name", tempBucketName)) err = sess.UpdateQuotaLimit(ctx, quotaBytes, resConfApikey, tempBucketName, endPoint, creds.IAMEndpoint) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to set quota limit on temp bucket", reqID), + logger.Error(ctx, cs.Logger, "Failed to set quota limit on temp bucket", zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) if delErr := sess.DeleteBucket(ctx, tempBucketName); delErr != nil { - log.Error(fmt.Sprintf("[%s] Failed to delete temp bucket after quota limit failure", reqID), + logger.Error(ctx, cs.Logger, "Failed to delete temp bucket after quota limit failure", zap.String("temp_bucket_name", tempBucketName), zap.Error(delErr)) } return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set bucket quota limit: %v", reqID, err)) } - log.Info(fmt.Sprintf("[%s] Successfully applied hard quota to temp bucket", reqID), + logger.Info(ctx, cs.Logger, "Successfully applied hard quota to temp bucket", zap.Int64("quota_bytes", quotaBytes), zap.String("temp_bucket_name", tempBucketName)) } if bucketVersioning != "" { enable := strings.ToLower(strings.TrimSpace(bucketVersioning)) == "true" - log.Info(fmt.Sprintf("[%s] Setting temp bucket versioning", reqID), + logger.Info(ctx, cs.Logger, "Setting temp bucket versioning", zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName)) err := sess.SetBucketVersioning(ctx, tempBucketName, enable) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to set temp bucket versioning", reqID), + logger.Error(ctx, cs.Logger, "Failed to set temp bucket versioning", zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) err1 := sess.DeleteBucket(ctx, tempBucketName) if err1 != nil { - log.Error(fmt.Sprintf("[%s] Failed to delete temp bucket after versioning failure", reqID), + logger.Error(ctx, cs.Logger, "Failed to delete temp bucket after versioning failure", zap.String("temp_bucket_name", tempBucketName), zap.Error(err1)) return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] cannot set versioning: %v and cannot delete temp bucket %s: %v", reqID, err, tempBucketName, err1)) } return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set versioning %t for temp bucket %s: %v", reqID, enable, tempBucketName, err)) } - log.Info(fmt.Sprintf("[%s] Temp bucket versioning set successfully", reqID), + logger.Info(ctx, cs.Logger, "Temp bucket versioning set successfully", zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName)) } - log.Info(fmt.Sprintf("[%s] Created temp bucket successfully", reqID), zap.String("temp_bucket_name", tempBucketName)) + logger.Info(ctx, cs.Logger, "Created temp bucket successfully", zap.String("temp_bucket_name", tempBucketName)) params["userProvidedBucket"] = "false" params["bucketName"] = tempBucketName } - log.Info(fmt.Sprintf("[%s] CreateVolume completed successfully", reqID), + logger.Info(ctx, cs.Logger, "CreateVolume completed successfully", zap.String("volume_id", volumeID), zap.String("bucket_name", params["bucketName"]), zap.Int64("capacity_bytes", req.GetCapacityRange().GetRequiredBytes())) @@ -397,153 +395,149 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { // Extract request ID from context reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] DeleteVolume started", reqID)) + logger.Info(ctx, cs.Logger, "DeleteVolume started") modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { - log.Error(fmt.Sprintf("[%s] Error modifying request", reqID), zap.Error(err)) + logger.Error(ctx, cs.Logger, "Error modifying request", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) } - log.Debug(fmt.Sprintf("[%s] DeleteVolume request details", reqID), zap.Any("request", modifiedRequest.(*csi.DeleteVolumeRequest))) + logger.Debug(ctx, cs.Logger, "DeleteVolume request details", zap.Any("request", modifiedRequest.(*csi.DeleteVolumeRequest))) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, cs.Logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } - log.Info(fmt.Sprintf("[%s] Deleting volume", reqID), zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "Deleting volume", zap.String("volume_id", volumeID)) secretMap := req.GetSecrets() - log.Info(fmt.Sprintf("[%s] Secrets received", reqID), zap.Int("secret_count", len(secretMap))) + logger.Info(ctx, cs.Logger, "Secrets received", zap.Int("secret_count", len(secretMap))) endPoint := secretMap["cosEndpoint"] locationConstraint := secretMap["locationConstraint"] if len(secretMap) == 0 { - log.Info(fmt.Sprintf("[%s] No secret in request, fetching from PV", reqID)) + logger.Info(ctx, cs.Logger, "No secret in request, fetching from PV") pv, err := cs.Stats.GetPV(volumeID) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to get PV", reqID), zap.String("volume_id", volumeID), zap.Error(err)) + logger.Error(ctx, cs.Logger, "Failed to get PV", zap.String("volume_id", volumeID), zap.Error(err)) return nil, err } - log.Debug(fmt.Sprintf("[%s] PV resource retrieved", reqID), zap.Any("pv", pv)) + logger.Debug(ctx, cs.Logger, "PV resource retrieved", zap.Any("pv", pv)) secretName := pv.Spec.CSI.NodePublishSecretRef.Name secretNamespace := pv.Spec.CSI.NodePublishSecretRef.Namespace if secretName == "" { - log.Error(fmt.Sprintf("[%s] Secret details not found in PV", reqID)) + logger.Error(ctx, cs.Logger, "Secret details not found in PV") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret details not found, could not fetch the secret", reqID)) } if secretNamespace == "" { - log.Warn(fmt.Sprintf("[%s] Secret namespace not found, using default namespace", reqID)) + logger.Warn(ctx, cs.Logger, "Secret namespace not found, using default namespace") secretNamespace = constants.DefaultNamespace } endPoint = pv.Spec.CSI.VolumeAttributes["cosEndpoint"] locationConstraint = pv.Spec.CSI.VolumeAttributes["locationConstraint"] - log.Info(fmt.Sprintf("[%s] Secret details found", reqID), + logger.Info(ctx, cs.Logger, "Secret details found", zap.String("secret_name", secretName), zap.String("secret_namespace", secretNamespace)) secret, err := cs.Stats.GetSecret(secretName, secretNamespace) if err != nil { - log.Error(fmt.Sprintf("[%s] Secret resource not found", reqID), zap.Error(err)) + logger.Error(ctx, cs.Logger, "Secret resource not found", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) } - secretMapCustom := parseCustomSecret(secret) - log.Info(fmt.Sprintf("[%s] Custom secret parsed successfully", reqID), zap.Int("secret_param_count", len(secretMapCustom))) + secretMapCustom := parseCustomSecret(ctx, secret, cs.Logger) + logger.Info(ctx, cs.Logger, "Custom secret parsed successfully", zap.Int("secret_param_count", len(secretMapCustom))) secretMap = secretMapCustom } - creds, err := getObjectStorageCredentialsFromSecret(secretMap, cs.iamEndpoint) + creds, err := getObjectStorageCredentialsFromSecret(ctx, secretMap, cs.iamEndpoint, cs.Logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Error getting credentials from secret", reqID), zap.Error(err)) + logger.Error(ctx, cs.Logger, "Error getting credentials from secret", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in getting credentials %v", reqID, err)) } - log.Info(fmt.Sprintf("[%s] Creating object storage session for deletion", reqID), + logger.Info(ctx, cs.Logger, "Creating object storage session for deletion", zap.String("endpoint", endPoint), zap.String("location_constraint", locationConstraint)) sess := cs.cosSession.NewObjectStorageSession(endPoint, locationConstraint, creds, cs.Logger) bucketToDelete, err := cs.Stats.BucketToDelete(volumeID) if err != nil { - log.Warn(fmt.Sprintf("[%s] No bucket to delete or error getting bucket info", reqID), zap.Error(err)) + logger.Warn(ctx, cs.Logger, "No bucket to delete or error getting bucket info", zap.Error(err)) return &csi.DeleteVolumeResponse{}, nil } if bucketToDelete != "" { - log.Info(fmt.Sprintf("[%s] Deleting bucket", reqID), zap.String("bucket_name", bucketToDelete)) + logger.Info(ctx, cs.Logger, "Deleting bucket", zap.String("bucket_name", bucketToDelete)) err = sess.DeleteBucket(ctx, bucketToDelete) if err != nil { - log.Warn(fmt.Sprintf("[%s] Cannot delete bucket", reqID), + logger.Warn(ctx, cs.Logger, "Cannot delete bucket", zap.String("bucket_name", bucketToDelete), zap.Error(err)) } else { - log.Info(fmt.Sprintf("[%s] Bucket deleted successfully", reqID), zap.String("bucket_name", bucketToDelete)) + logger.Info(ctx, cs.Logger, "Bucket deleted successfully", zap.String("bucket_name", bucketToDelete)) } } else { - log.Info(fmt.Sprintf("[%s] No bucket to delete", reqID)) + logger.Info(ctx, cs.Logger, "No bucket to delete") } - log.Info(fmt.Sprintf("[%s] DeleteVolume completed successfully", reqID), zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "DeleteVolume completed successfully", zap.String("volume_id", volumeID)) return &csi.DeleteVolumeResponse{}, nil } func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ControllerPublishVolume request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ControllerPublishVolume not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ControllerPublishVolume request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ControllerPublishVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerPublishVolume", reqID)) } func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ControllerUnpublishVolume request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ControllerUnpublishVolume not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ControllerUnpublishVolume request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ControllerUnpublishVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerUnpublishVolume", reqID)) } func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] ValidateVolumeCapabilities started", reqID)) - log.Debug(fmt.Sprintf("[%s] ValidateVolumeCapabilities request", reqID), zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ValidateVolumeCapabilities started") + logger.Debug(ctx, cs.Logger, "ValidateVolumeCapabilities request", zap.Any("request", req)) // Validate Arguments volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, cs.Logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } volCaps := req.GetVolumeCapabilities() if len(volCaps) == 0 { - log.Error(fmt.Sprintf("[%s] Volume capabilities missing in request", reqID)) + logger.Error(ctx, cs.Logger, "Volume capabilities missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capabilities missing in request", reqID)) } var confirmed *csi.ValidateVolumeCapabilitiesResponse_Confirmed if isValidVolumeCapabilities(volCaps) { - log.Info(fmt.Sprintf("[%s] Volume capabilities are valid", reqID), zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "Volume capabilities are valid", zap.String("volume_id", volumeID)) confirmed = &csi.ValidateVolumeCapabilitiesResponse_Confirmed{VolumeCapabilities: volCaps} } else { - log.Warn(fmt.Sprintf("[%s] Volume capabilities are invalid", reqID), zap.String("volume_id", volumeID)) + logger.Warn(ctx, cs.Logger, "Volume capabilities are invalid", zap.String("volume_id", volumeID)) } - log.Info(fmt.Sprintf("[%s] ValidateVolumeCapabilities completed", reqID), zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "ValidateVolumeCapabilities completed", zap.String("volume_id", volumeID)) return &csi.ValidateVolumeCapabilitiesResponse{ Confirmed: confirmed, }, nil @@ -551,28 +545,23 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ListVolumes request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ListVolumes not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ListVolumes request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ListVolumes not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListVolumes", reqID)) } func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] GetCapacity request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] GetCapacity not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "GetCapacity request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "GetCapacity not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] GetCapacity", reqID)) } func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { - reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] ControllerGetCapabilities started", reqID)) - log.Debug(fmt.Sprintf("[%s] ControllerGetCapabilities request", reqID), zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ControllerGetCapabilities started") + logger.Debug(ctx, cs.Logger, "ControllerGetCapabilities request", zap.Any("request", req)) var caps []*csi.ControllerServiceCapability for _, cap := range controllerCapabilities { @@ -586,66 +575,60 @@ func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req * caps = append(caps, c) } - log.Info(fmt.Sprintf("[%s] ControllerGetCapabilities completed", reqID), zap.Int("capability_count", len(caps))) + logger.Info(ctx, cs.Logger, "ControllerGetCapabilities completed", zap.Int("capability_count", len(caps))) return &csi.ControllerGetCapabilitiesResponse{Capabilities: caps}, nil } func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] CreateSnapshot request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] CreateSnapshot not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "CreateSnapshot request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "CreateSnapshot not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] CreateSnapshot", reqID)) } func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] DeleteSnapshot request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] DeleteSnapshot not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "DeleteSnapshot request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "DeleteSnapshot not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] DeleteSnapshot", reqID)) } func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ListSnapshots request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ListSnapshots not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ListSnapshots request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ListSnapshots not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListSnapshots", reqID)) } func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ControllerExpandVolume request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ControllerExpandVolume not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ControllerExpandVolume request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ControllerExpandVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerExpandVolume", reqID)) } func (cs *controllerServer) ControllerGetVolume(ctx context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ControllerGetVolume request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ControllerGetVolume not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ControllerGetVolume request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ControllerGetVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerGetVolume", reqID)) } func (cs *controllerServer) ControllerModifyVolume(ctx context.Context, req *csi.ControllerModifyVolumeRequest) (*csi.ControllerModifyVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := cs.Logger.With(zap.String("request_id", reqID)) - log.Debug(fmt.Sprintf("[%s] ControllerModifyVolume request", reqID), zap.Any("request", req)) - log.Info(fmt.Sprintf("[%s] ControllerModifyVolume not implemented", reqID)) + logger.Debug(ctx, cs.Logger, "ControllerModifyVolume request", zap.Any("request", req)) + logger.Info(ctx, cs.Logger, "ControllerModifyVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerModifyVolume", reqID)) } -func getObjectStorageCredentialsFromSecret(secretMap map[string]string, iamEP string) (*s3client.ObjectStorageCredentials, error) { - log.Info("Getting object storage credentials from secret") +func getObjectStorageCredentialsFromSecret(ctx context.Context, secretMap map[string]string, iamEP string, log *zap.Logger) (*s3client.ObjectStorageCredentials, error) { + logger.Info(ctx, log, "Getting object storage credentials from secret") var ( accessKey string secretKey string @@ -688,8 +671,8 @@ func getObjectStorageCredentialsFromSecret(secretMap map[string]string, iamEP st }, nil } -func parseCustomSecret(secret *v1.Secret, log *zap.Logger) map[string]string { - log.Info("Parsing custom secret") +func parseCustomSecret(ctx context.Context, secret *v1.Secret, log *zap.Logger) map[string]string { + logger.Info(ctx, log, "Parsing custom secret") secretMapCustom := make(map[string]string) var ( @@ -776,8 +759,8 @@ func parseCustomSecret(secret *v1.Secret, log *zap.Logger) map[string]string { return secretMapCustom } -func getTempBucketName(mounterType, volumeID string) string { - log.Info("Getting temp bucket name", zap.String("mounter_type", mounterType)) +func getTempBucketName(ctx context.Context, mounterType, volumeID string, log *zap.Logger) string { + logger.Info(ctx, log, "Getting temp bucket name", zap.String("mounter_type", mounterType)) currentTime := time.Now() timestamp := currentTime.Format("20060102150405") @@ -786,23 +769,21 @@ func getTempBucketName(mounterType, volumeID string) string { } func createBucket(ctx context.Context, sess s3client.ObjectStorageSession, bucketName, kpRootKeyCrn string, log *zap.Logger) error { - reqID := requestid.FromContext(ctx) - msg, err := sess.CreateBucket(ctx, bucketName, kpRootKeyCrn) if msg != "" { - log.Info(fmt.Sprintf("[%s] Bucket creation info", reqID), zap.String("message", msg)) + logger.Info(ctx, log, "Bucket creation info", zap.String("message", msg)) } if err != nil { var apiErr smithy.APIError if errors.As(err, &apiErr) && apiErr.ErrorCode() == "BucketAlreadyExists" { - log.Warn(fmt.Sprintf("[%s] Bucket already exists", reqID), zap.String("bucket", bucketName)) + logger.Warn(ctx, log, "Bucket already exists", zap.String("bucket", bucketName)) } else { - log.Error(fmt.Sprintf("[%s] Unable to create bucket", reqID), zap.String("bucket", bucketName), zap.Error(err)) + logger.Error(ctx, log, "Unable to create bucket", zap.String("bucket", bucketName), zap.Error(err)) return errors.New("unable to create the bucket") } } if err := sess.CheckBucketAccess(ctx, bucketName); err != nil { - log.Error(fmt.Sprintf("[%s] Unable to access bucket", reqID), zap.String("bucket", bucketName), zap.Error(err)) + logger.Error(ctx, log, "Unable to access bucket", zap.String("bucket", bucketName), zap.Error(err)) return errors.New("unable to access the bucket") } return nil diff --git a/pkg/driver/nodeserver.go b/pkg/driver/nodeserver.go index 35a7967f..fec60265 100644 --- a/pkg/driver/nodeserver.go +++ b/pkg/driver/nodeserver.go @@ -15,7 +15,6 @@ import ( "fmt" "github.com/IBM/ibm-object-csi-driver/pkg/constants" - "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" "github.com/IBM/ibm-object-csi-driver/pkg/requestid" @@ -46,7 +45,7 @@ type NodeServerConfig struct { func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeStageVolume started", reqID)) log.Debug(fmt.Sprintf("[%s] NodeStageVolume request", reqID), zap.Any("request", req)) @@ -71,7 +70,7 @@ func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeUnstageVolume started", reqID)) log.Debug(fmt.Sprintf("[%s] NodeUnstageVolume request", reqID), zap.Any("request", req)) @@ -96,7 +95,7 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodePublishVolume started", reqID)) @@ -230,7 +229,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeUnpublishVolume started", reqID)) log.Debug(fmt.Sprintf("[%s] NodeUnpublishVolume request", reqID), zap.Any("request", req)) @@ -270,7 +269,7 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeGetVolumeStats started", reqID)) log.Debug(fmt.Sprintf("[%s] NodeGetVolumeStats request", reqID), zap.Any("request", req)) @@ -351,7 +350,7 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo func (ns *nodeServer) NodeExpandVolume(ctx context.Context, _ *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeExpandVolume not implemented", reqID)) return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] NodeExpandVolume is not implemented", reqID)) @@ -359,7 +358,7 @@ func (ns *nodeServer) NodeExpandVolume(ctx context.Context, _ *csi.NodeExpandVol func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeGetCapabilities started", reqID)) log.Debug(fmt.Sprintf("[%s] NodeGetCapabilities request", reqID), zap.Any("request", req)) @@ -382,7 +381,7 @@ func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetC func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.Logger.With(zap.String("request_id", reqID)) + log := ns.logger.With(zap.String("request_id", reqID)) log.Info(fmt.Sprintf("[%s] NodeGetInfo started", reqID)) log.Debug(fmt.Sprintf("[%s] NodeGetInfo request", reqID), zap.Any("request", req)) diff --git a/pkg/driver/s3-driver.go b/pkg/driver/s3-driver.go index fea1c4bb..2f52b823 100644 --- a/pkg/driver/s3-driver.go +++ b/pkg/driver/s3-driver.go @@ -24,7 +24,6 @@ import ( pkgUtils "github.com/IBM/ibm-object-csi-driver/pkg/utils" csi "github.com/container-storage-interface/spec/lib/go/csi" "go.uber.org/zap" - "k8s.io/klog/v2" ) var ( From d4cae4e5a3f4bafefeb87aca63d8e863652a1899 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 26 May 2026 11:44:17 +0530 Subject: [PATCH 06/64] klog to zap migration --- pkg/mounter/fake_mounter-rclone.go | 12 ++- pkg/mounter/utils/mounter_utils.go | 137 ++++++++++++++++++++--------- pkg/s3client/fake_s3client.go | 13 +-- 3 files changed, 112 insertions(+), 50 deletions(-) diff --git a/pkg/mounter/fake_mounter-rclone.go b/pkg/mounter/fake_mounter-rclone.go index dec9652a..245ea295 100644 --- a/pkg/mounter/fake_mounter-rclone.go +++ b/pkg/mounter/fake_mounter-rclone.go @@ -1,6 +1,12 @@ +//go:build linux +// +build linux + package mounter -import "errors" +import ( + "context" + "errors" +) type fakercloneMounter struct { bucketName string @@ -33,14 +39,14 @@ func fakenewRcloneMounter(isFailedMount, isFailedUnmount bool) Mounter { } } -func (rclone *fakercloneMounter) Mount(source string, target string) error { +func (rclone *fakercloneMounter) Mount(ctx context.Context, source string, target string) error { if rclone.isFailedMount { return errors.New("failed to mount rclone") } return nil } -func (rclone *fakercloneMounter) Unmount(target string) error { +func (rclone *fakercloneMounter) Unmount(ctx context.Context, target string) error { if rclone.isFailedUnmount { return errors.New("failed to unmount rclone") } diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index d2e1f8c6..c3f533ca 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -15,7 +15,7 @@ import ( "github.com/IBM/ibm-object-csi-driver/pkg/constants" "github.com/mitchellh/go-ps" - "k8s.io/klog/v2" + "go.uber.org/zap" k8sMountUtils "k8s.io/mount-utils" ) @@ -24,6 +24,9 @@ var commandWithCtx = exec.CommandContext var ErrTimeoutWaitProcess = errors.New("timeout waiting for process to end") +// Package-level logger for mounter utils +var mounterUtilLogger, _ = zap.NewProduction() + type MounterUtils interface { FuseUnmount(path string) error FuseMount(path string, comm string, args []string) error @@ -33,8 +36,11 @@ type MounterOptsUtils struct { } func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) error { - klog.Info("-FuseMount-") - klog.Infof("FuseMount: params:\n\tpath: <%s>\n\tcommand: <%s>\n\targs: <%v>", path, comm, args) + mounterUtilLogger.Info("FuseMount started") + mounterUtilLogger.Info("FuseMount parameters", + zap.String("path", path), + zap.String("command", comm), + zap.Strings("args", args)) ctx, cancel := context.WithCancel(context.Background()) var mounted bool @@ -47,98 +53,125 @@ func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) e cmd := commandWithCtx(ctx, comm, args...) err := cmd.Start() if err != nil { - klog.Errorf("FuseMount: command start failed: mounter=%s, args=%v, error=%v", comm, args, err) + mounterUtilLogger.Error("FuseMount: command start failed", + zap.String("mounter", comm), + zap.Strings("args", args), + zap.Error(err)) return fmt.Errorf("FuseMount: '%s' command start failed: %v", comm, err) } - klog.Infof("FuseMount: command 'start' succeeded for '%s' mounter", comm) + mounterUtilLogger.Info("FuseMount: command start succeeded", zap.String("mounter", comm)) waitCh := make(chan error, 1) mountCh := make(chan error, 1) go func() { - klog.Infof("FuseMount: cmd.Wait() goroutine start for mounter=%s, path=%v", comm, path) + mounterUtilLogger.Info("FuseMount: cmd.Wait() goroutine start", + zap.String("mounter", comm), + zap.String("path", path)) waitCh <- cmd.Wait() - klog.Infof("FuseMount: cmd.Wait() goroutine end for mounter=%s, path=%v", comm, path) + mounterUtilLogger.Info("FuseMount: cmd.Wait() goroutine end", + zap.String("mounter", comm), + zap.String("path", path)) }() go func() { - klog.Infof("FuseMount: waitForMount() goroutine start for mounter=%s, path=%v", comm, path) + mounterUtilLogger.Info("FuseMount: waitForMount() goroutine start", + zap.String("mounter", comm), + zap.String("path", path)) mountCh <- waitForMount(ctx, path, 2*time.Second, 30*time.Second) // kubelet retries NodePublishVolume after 120 seconds - klog.Infof("FuseMount: waitForMount() goroutine end for mounter=%s, path=%v", comm, path) + mounterUtilLogger.Info("FuseMount: waitForMount() goroutine end", + zap.String("mounter", comm), + zap.String("path", path)) }() select { case err := <-waitCh: if err != nil { - klog.Warningf("FuseMount: command 'wait' failed: mounter=%s, args=%v, error=%v", comm, args, err) - klog.Infof("FuseMount: checking if path already exists and is a mountpoint: path=%s", path) + mounterUtilLogger.Warn("FuseMount: command wait failed", + zap.String("mounter", comm), + zap.Strings("args", args), + zap.Error(err)) + mounterUtilLogger.Info("FuseMount: checking if path already exists and is a mountpoint", + zap.String("path", path)) if isMount, err1 := isMountpoint(path); err1 == nil && isMount { // check if bucket already got mounted - klog.Infof("bucket is already mounted using '%s' mounter", comm) + mounterUtilLogger.Info("Bucket is already mounted", zap.String("mounter", comm)) mounted = true return nil } return fmt.Errorf("'%s' mount failed: %v", comm, err) } - klog.Infof("FuseMount: command 'wait' succeeded for '%s' mounter", comm) + mounterUtilLogger.Info("FuseMount: command wait succeeded", zap.String("mounter", comm)) if err := <-mountCh; err != nil { return err } case err := <-mountCh: if err != nil { - klog.Errorf("FuseMount: path is not mountpoint. Mount failed: mounter=%s, path=%s", comm, path) + mounterUtilLogger.Error("FuseMount: path is not mountpoint, mount failed", + zap.String("mounter", comm), + zap.String("path", path)) return fmt.Errorf("'%s' mount failed: %v", comm, err) } } - klog.Infof("bucket mounted successfully using '%s' mounter", comm) + mounterUtilLogger.Info("Bucket mounted successfully", zap.String("mounter", comm)) mounted = true return nil } func (su *MounterOptsUtils) FuseUnmount(path string) error { - klog.Info("-FuseUnmount-") + mounterUtilLogger.Info("FuseUnmount started", zap.String("path", path)) // check if mountpoint exists isMount, checkMountErr := isMountpoint(path) if isMount || checkMountErr != nil { - klog.Infof("isMountpoint %v", isMount) + mounterUtilLogger.Info("isMountpoint check", zap.Bool("is_mount", isMount)) err := unmount(path, 0) if err != nil { - klog.Warningf("Standard unmount failed for %s: %v. Trying lazy unmount...", path, err) + mounterUtilLogger.Warn("Standard unmount failed, trying lazy unmount", + zap.String("path", path), + zap.Error(err)) // Try lazy (MNT_DETACH) unmount err = unmount(path, syscall.MNT_DETACH) if err != nil { - klog.Warningf("Lazy unmount failed for %s: %v. Trying force unmount...", path, err) + mounterUtilLogger.Warn("Lazy unmount failed, trying force unmount", + zap.String("path", path), + zap.Error(err)) // Try force unmount as last resort err = unmount(path, syscall.MNT_FORCE) if err != nil { - klog.Errorf("Force unmount failed for %s: %v", path, err) + mounterUtilLogger.Error("Force unmount failed", + zap.String("path", path), + zap.Error(err)) return fmt.Errorf("all unmount attempts failed for %s: %v", path, err) } - klog.Infof("Force unmounted %s successfully", path) + mounterUtilLogger.Info("Force unmounted successfully", zap.String("path", path)) } else { - klog.Infof("Lazy unmounted %s successfully", path) + mounterUtilLogger.Info("Lazy unmounted successfully", zap.String("path", path)) } } else { - klog.Infof("Unmounted %s with standard unmount successfully", path) + mounterUtilLogger.Info("Unmounted with standard unmount successfully", zap.String("path", path)) } } // as fuse quits immediately, we will try to wait until the process is done process, err := findFuseMountProcess(path) if err != nil { - klog.Infof("Error getting PID of fuse mount: %s", err) + mounterUtilLogger.Info("Error getting PID of fuse mount", zap.Error(err)) return nil } if process == nil { - klog.Infof("Unable to find PID of fuse mount %s, it must have finished already", path) + mounterUtilLogger.Info("Unable to find PID of fuse mount, it must have finished already", + zap.String("path", path)) return nil } - klog.Infof("Found fuse pid %v of mount %s, checking if it still runs", process.Pid, path) + mounterUtilLogger.Info("Found fuse pid of mount, checking if it still runs", + zap.Int("pid", process.Pid), + zap.String("path", path)) err = waitForProcess(process, 1) if errors.Is(err, ErrTimeoutWaitProcess) { - klog.Infof("timeout waiting for pid %d to end, killing process", process.Pid) + mounterUtilLogger.Info("Timeout waiting for pid to end, killing process", + zap.Int("pid", process.Pid)) return process.Kill() } @@ -146,24 +179,30 @@ func (su *MounterOptsUtils) FuseUnmount(path string) error { } func isMountpoint(pathname string) (bool, error) { - klog.Infof("Checking if path is mountpoint: Pathname - %s", pathname) + mounterUtilLogger.Info("Checking if path is mountpoint", zap.String("pathname", pathname)) out, err := exec.Command("mountpoint", pathname).CombinedOutput() outStr := strings.ToLower(strings.TrimSpace(string(out))) - klog.Infof("mountpoint status for path '%s', error: %v, output: %s", pathname, err, string(out)) + mounterUtilLogger.Info("Mountpoint status", + zap.String("path", pathname), + zap.Error(err), + zap.String("output", string(out))) if err != nil { if strings.HasSuffix(outStr, "transport endpoint is not connected") { return true, nil } if strings.HasSuffix(outStr, "is not a mountpoint") { - klog.Infof("Path is NOT a mountpoint: pathname - %s", pathname) + mounterUtilLogger.Info("Path is NOT a mountpoint", zap.String("pathname", pathname)) return false, nil } - klog.Errorf("Failed to check mountpoint for path '%s', error: %v, output: %s", pathname, err, string(out)) + mounterUtilLogger.Error("Failed to check mountpoint for path", + zap.String("path", pathname), + zap.Error(err), + zap.String("output", string(out))) return false, fmt.Errorf("failed to check mountpoint for path '%s', error: %v, output: %s", pathname, err, string(out)) } if strings.HasSuffix(outStr, "is a mountpoint") { - klog.Infof("Path is a mountpoint: pathname - %s", pathname) + mounterUtilLogger.Info("Path is a mountpoint", zap.String("pathname", pathname)) return true, nil } @@ -180,16 +219,21 @@ func waitForMount(ctx context.Context, path string, initialDelay, timeout time.D select { case <-ctx.Done(): err := ctx.Err() - klog.Infof("waitForMount: context is done, error: %v", err) + mounterUtilLogger.Info("waitForMount: context is done", zap.Error(err)) return err default: isMount, err := k8sMountUtils.New("").IsMountPoint(path) if err == nil && isMount { - klog.Infof("Path is a mountpoint: pathname: %s", path) + mounterUtilLogger.Info("Path is a mountpoint", zap.String("pathname", path)) return nil } - klog.Infof("Mountpoint check in progress: attempt=%d, path=%s, isMount=%v, err=%v, timeout=%v", attempt, path, isMount, err, timeout) + mounterUtilLogger.Info("Mountpoint check in progress", + zap.Int("attempt", attempt), + zap.String("path", path), + zap.Bool("is_mount", isMount), + zap.Error(err), + zap.Duration("timeout", timeout)) time.Sleep(constants.Interval) elapsed += constants.Interval if elapsed >= timeout { @@ -208,11 +252,15 @@ func findFuseMountProcess(path string) (*os.Process, error) { for _, p := range processes { cmdLine, err := getCmdLine(p.Pid()) if err != nil { - klog.Errorf("Unable to get cmdline of PID %v: %s", p.Pid(), err) + mounterUtilLogger.Error("Unable to get cmdline of PID", + zap.Int("pid", p.Pid()), + zap.Error(err)) continue } if strings.Contains(cmdLine, path) { - klog.Infof("Found matching pid %v on path %s", p.Pid(), path) + mounterUtilLogger.Info("Found matching pid on path", + zap.Int("pid", p.Pid()), + zap.String("path", path)) return os.FindProcess(p.Pid()) } } @@ -235,21 +283,28 @@ func waitForProcess(p *os.Process, backoff int) error { } cmdLine, err := getCmdLine(p.Pid) if err != nil { - klog.Warningf("Error checking cmdline of PID %v, assuming it is dead: %s", p.Pid, err) + mounterUtilLogger.Warn("Error checking cmdline of PID, assuming it is dead", + zap.Int("pid", p.Pid), + zap.Error(err)) return nil } if cmdLine == "" { // ignore defunct processes // TODO: debug why this happens in the first place // seems to only happen on k8s, not on local docker - klog.Warning("Fuse process seems dead, returning") + mounterUtilLogger.Warn("Fuse process seems dead, returning") return nil } if err := p.Signal(syscall.Signal(0)); err != nil { - klog.Warningf("Fuse process does not seem active or we are unprivileged: %s", err) + mounterUtilLogger.Warn("Fuse process does not seem active or we are unprivileged", + zap.Error(err)) return nil } - klog.Infof("Fuse process with PID %v still active, waiting... %v", p.Pid, backoff) + mounterUtilLogger.Info("Fuse process still active, waiting", + zap.Int("pid", p.Pid), + zap.Int("backoff", backoff)) time.Sleep(time.Duration(500) * time.Millisecond) return waitForProcess(p, backoff+1) } + +// Made with Bob diff --git a/pkg/s3client/fake_s3client.go b/pkg/s3client/fake_s3client.go index 99e41a87..7499269b 100644 --- a/pkg/s3client/fake_s3client.go +++ b/pkg/s3client/fake_s3client.go @@ -1,6 +1,7 @@ package s3client import ( + "context" "errors" "go.uber.org/zap" @@ -26,39 +27,39 @@ func (f *FakeCOSSessionFactory) NewObjectStorageSession(endpoint, region string, } } -func (s *fakeCOSSession) CheckBucketAccess(bucket string) error { +func (s *fakeCOSSession) CheckBucketAccess(ctx context.Context, bucket string) error { if s.factory.FailCheckBucketAccess { return errors.New("failed to check bucket access") } return nil } -func (s *fakeCOSSession) SetBucketVersioning(bucket string, enable bool) error { +func (s *fakeCOSSession) SetBucketVersioning(ctx context.Context, bucket string, enable bool) error { if s.factory.FailBucketVersioning { return errors.New("failed to set bucket versioning") } return nil } -func (s *fakeCOSSession) CheckObjectPathExistence(bucket, objectpath string) (bool, error) { +func (s *fakeCOSSession) CheckObjectPathExistence(ctx context.Context, bucket, objectpath string) (bool, error) { return true, nil } -func (s *fakeCOSSession) CreateBucket(bucket, kpRootKeyCrn string) (string, error) { +func (s *fakeCOSSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn string) (string, error) { if s.factory.FailCreateBucket { return "", errors.New("failed to create bucket") } return "", nil } -func (s *fakeCOSSession) DeleteBucket(bucket string) error { +func (s *fakeCOSSession) DeleteBucket(ctx context.Context, bucket string) error { if s.factory.FailDeleteBucket { return errors.New("failed to delete bucket") } return nil } -func (s *fakeCOSSession) UpdateQuotaLimit(quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { +func (s *fakeCOSSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { if s.factory.FailUpdateQuotaLimit { return errors.New("failed to update quota limit") } From 31bd5b47cef6cffdab3b40917fe88fa24a57e9f1 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 26 May 2026 19:11:29 +0530 Subject: [PATCH 07/64] build issue fix --- pkg/mounter/mounter-rclone_test.go | 29 ++++++++++++++++------------ pkg/mounter/mounter-s3fs_test.go | 31 +++++++++++++++++------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/pkg/mounter/mounter-rclone_test.go b/pkg/mounter/mounter-rclone_test.go index 5a58250c..c9fa5cc5 100644 --- a/pkg/mounter/mounter-rclone_test.go +++ b/pkg/mounter/mounter-rclone_test.go @@ -1,12 +1,17 @@ +//go:build linux +// +build linux + package mounter import ( + "context" "errors" "os" "testing" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" "github.com/stretchr/testify/assert" + "go.uber.org/zap" ) var ( @@ -142,7 +147,7 @@ func TestRcloneMount_NodeServer_Positive(t *testing.T) { return nil } - err := rclone.Mount(source, target) + err := rclone.Mount(context.Background(), source, target) assert.NoError(t, err) } @@ -153,7 +158,7 @@ func TestRcloneMount_CreateConfigFails_Negative(t *testing.T) { return errors.New("failed to create config file") } - err := rclone.Mount(source, target) + err := rclone.Mount(context.Background(), source, target) assert.Error(t, err) assert.EqualError(t, err, "failed to create config file") } @@ -178,11 +183,11 @@ func TestRcloneMount_WorkerNode_Positive(t *testing.T) { createConfigWrap = func(_ string, _ *RcloneMounter) error { return nil } - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return nil } - err := rclone.Mount(source, target) + err := rclone.Mount(context.Background(), source, target) assert.NoError(t, err) } @@ -206,11 +211,11 @@ func TestRcloneMount_WorkerNode_Negative(t *testing.T) { createConfigWrap = func(_ string, _ *RcloneMounter) error { return nil } - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return errors.New("failed to create http request") } - err := rclone.Mount(source, target) + err := rclone.Mount(context.Background(), source, target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to create http request") } @@ -226,7 +231,7 @@ func TestRcloneUnmount_NodeServer(t *testing.T) { }, })} - err := rclone.Unmount(target) + err := rclone.Unmount(context.Background(), target) assert.NoError(t, err) } @@ -241,11 +246,11 @@ func TestRcloneUnmount_WorkerNode(t *testing.T) { }, })} - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return nil } - err := rclone.Unmount(target) + err := rclone.Unmount(context.Background(), target) assert.NoError(t, err) } @@ -258,11 +263,11 @@ func TestRcloneUnmount_WorkerNode_Negative(t *testing.T) { }, })} - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return errors.New("failed to create http request") } - err := rclone.Unmount(target) + err := rclone.Unmount(context.Background(), target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to create http request") } @@ -278,7 +283,7 @@ func TestRcloneUnmount_NodeServer_Negative(t *testing.T) { }, })} - err := rclone.Unmount(target) + err := rclone.Unmount(context.Background(), target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to unmount") } diff --git a/pkg/mounter/mounter-s3fs_test.go b/pkg/mounter/mounter-s3fs_test.go index 430b8f2c..32131726 100644 --- a/pkg/mounter/mounter-s3fs_test.go +++ b/pkg/mounter/mounter-s3fs_test.go @@ -1,6 +1,10 @@ +//go:build linux +// +build linux + package mounter import ( + "context" "errors" "os" "testing" @@ -8,6 +12,7 @@ import ( "github.com/IBM/ibm-object-csi-driver/pkg/constants" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" "github.com/stretchr/testify/assert" + "go.uber.org/zap" ) var ( @@ -88,7 +93,7 @@ func TestS3FSMount_NodeServer_Positive(t *testing.T) { ObjectPath: "test-objectPath", } - err := s3fs.Mount(source, target) + err := s3fs.Mount(context.Background(), source, target) assert.NoError(t, err) } @@ -101,7 +106,7 @@ func TestS3FSMount_WorkerNode_Positive(t *testing.T) { writePassWrap = func(_, _ string) error { return nil } - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return nil } @@ -114,7 +119,7 @@ func TestS3FSMount_WorkerNode_Positive(t *testing.T) { AuthType: "hmac", } - err := s3fs.Mount(source, target) + err := s3fs.Mount(context.Background(), source, target) assert.NoError(t, err) } @@ -125,7 +130,7 @@ func TestMount_CreateDirFails_Negative(t *testing.T) { return errors.New("failed to create directory") } - err := s3fs.Mount(source, target) + err := s3fs.Mount(context.Background(), source, target) assert.Error(t, err) assert.Contains(t, err.Error(), "Cannot create directory") } @@ -140,7 +145,7 @@ func TestMount_FailedToCreatePassFile_Negative(t *testing.T) { s3fs := &S3fsMounter{} - err := s3fs.Mount(source, target) + err := s3fs.Mount(context.Background(), source, target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to create file") } @@ -154,13 +159,13 @@ func TestS3FSMount_WorkerNode_Negative(t *testing.T) { writePassWrap = func(_, _ string) error { return nil } - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return errors.New("failed to perform http request") } s3fs := &S3fsMounter{} - err := s3fs.Mount(source, target) + err := s3fs.Mount(context.Background(), source, target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to perform http request") } @@ -176,7 +181,7 @@ func TestUnmount_NodeServer(t *testing.T) { }, })} - err := s3fs.Unmount(target) + err := s3fs.Unmount(context.Background(), target) assert.NoError(t, err) } @@ -191,11 +196,11 @@ func TestUnmount_WorkerNode(t *testing.T) { }, })} - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return nil } - err := s3fs.Unmount(target) + err := s3fs.Unmount(context.Background(), target) assert.NoError(t, err) } @@ -208,11 +213,11 @@ func TestUnmount_WorkerNode_Negative(t *testing.T) { }, })} - mounterRequest = func(_, _ string) error { + mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return errors.New("failed to create http request") } - err := s3fs.Unmount(target) + err := s3fs.Unmount(context.Background(), target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to create http request") } @@ -228,7 +233,7 @@ func TestUnmount_NodeServer_Negative(t *testing.T) { }, })} - err := s3fs.Unmount(target) + err := s3fs.Unmount(context.Background(), target) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to unmount") } From d7babd4d1b1d5ae1f91f77f4b6cb3e69fb7cc6e6 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 26 May 2026 20:24:54 +0530 Subject: [PATCH 08/64] build fix unused logger --- pkg/mounter/mounter.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go index 28deda9b..21f2d460 100644 --- a/pkg/mounter/mounter.go +++ b/pkg/mounter/mounter.go @@ -14,7 +14,6 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" - "github.com/IBM/ibm-object-csi-driver/pkg/logger" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "go.uber.org/zap" @@ -134,7 +133,7 @@ func writePass(pwFileName string, pwFileContent string) error { func createCOSCSIMounterRequest(ctx context.Context, payload string, url string, log *zap.Logger) error { reqID := requestid.FromContext(ctx) - + // Get socket path socketPath := os.Getenv(constants.COSCSIMounterSocketPathEnv) if socketPath == "" { @@ -169,7 +168,7 @@ func createCOSCSIMounterRequest(ctx context.Context, payload string, url string, } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Request-ID", reqID) // Add request ID to HTTP header - + log.Info(fmt.Sprintf("[%s] Sending request to cos-csi-mounter", reqID), zap.String("url", url)) response, err := client.Do(req) if err != nil { From 43178288953c4bc7f4ad7d13521dc7923be52d78 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 26 May 2026 21:29:43 +0530 Subject: [PATCH 09/64] build fix --- cos-csi-mounter/server/fake_server.go | 4 +-- cos-csi-mounter/server/rclone.go | 3 ++ cos-csi-mounter/server/s3fs.go | 3 ++ cos-csi-mounter/server/server.go | 7 +++-- cos-csi-mounter/server/utils.go | 3 ++ pkg/mounter/fake_mounter.go | 3 ++ pkg/mounter/mounter.go | 3 ++ pkg/mounter/mounter_stub.go | 38 +++++++++++++++++++++++++ pkg/mounter/utils/mounter_utils_stub.go | 21 ++++++++++++++ 9 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 pkg/mounter/mounter_stub.go create mode 100644 pkg/mounter/utils/mounter_utils_stub.go diff --git a/cos-csi-mounter/server/fake_server.go b/cos-csi-mounter/server/fake_server.go index fe11f584..d6b92610 100644 --- a/cos-csi-mounter/server/fake_server.go +++ b/cos-csi-mounter/server/fake_server.go @@ -1,5 +1,5 @@ -//go:build !unit_test -// +build !unit_test +//go:build linux +// +build linux package main diff --git a/cos-csi-mounter/server/rclone.go b/cos-csi-mounter/server/rclone.go index cb28e223..74e40e77 100644 --- a/cos-csi-mounter/server/rclone.go +++ b/cos-csi-mounter/server/rclone.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/cos-csi-mounter/server/s3fs.go b/cos-csi-mounter/server/s3fs.go index 480f6a0c..58575309 100644 --- a/cos-csi-mounter/server/s3fs.go +++ b/cos-csi-mounter/server/s3fs.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index 1ae1ea0c..ed226aa2 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( @@ -165,7 +168,7 @@ func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) reqID = "unknown" } log := logger.With(zap.String("request_id", reqID)) - + var request MountRequest if err := c.BindJSON(&request); err != nil { @@ -227,7 +230,7 @@ func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { reqID = "unknown" } log := logger.With(zap.String("request_id", reqID)) - + var request struct { Path string `json:"path"` } diff --git a/cos-csi-mounter/server/utils.go b/cos-csi-mounter/server/utils.go index e2858b11..c911ea28 100644 --- a/cos-csi-mounter/server/utils.go +++ b/cos-csi-mounter/server/utils.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/pkg/mounter/fake_mounter.go b/pkg/mounter/fake_mounter.go index a215b3ea..a76be730 100644 --- a/pkg/mounter/fake_mounter.go +++ b/pkg/mounter/fake_mounter.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package mounter import "github.com/IBM/ibm-object-csi-driver/pkg/constants" diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go index 21f2d460..af0aa9b6 100644 --- a/pkg/mounter/mounter.go +++ b/pkg/mounter/mounter.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package mounter import ( diff --git a/pkg/mounter/mounter_stub.go b/pkg/mounter/mounter_stub.go new file mode 100644 index 00000000..976660c3 --- /dev/null +++ b/pkg/mounter/mounter_stub.go @@ -0,0 +1,38 @@ +//go:build !linux +// +build !linux + +package mounter + +import ( + "context" + "fmt" +) + +type CSIMounterFactory struct{} + +type NewMounterFactory interface { + NewMounter(attrib map[string]string, secretMap map[string]string, mountFlags []string, defaultMOMap map[string]string) Mounter +} + +type Mounter interface { + Mount(ctx context.Context, source string, target string) error + Unmount(ctx context.Context, target string) error +} + +func NewCSIMounterFactory() *CSIMounterFactory { + return &CSIMounterFactory{} +} + +func (s *CSIMounterFactory) NewMounter(attrib map[string]string, secretMap map[string]string, mountFlags []string, defaultMOMap map[string]string) Mounter { + return &stubMounter{} +} + +type stubMounter struct{} + +func (s *stubMounter) Mount(ctx context.Context, source string, target string) error { + return fmt.Errorf("mounter not supported on this platform") +} + +func (s *stubMounter) Unmount(ctx context.Context, target string) error { + return fmt.Errorf("mounter not supported on this platform") +} diff --git a/pkg/mounter/utils/mounter_utils_stub.go b/pkg/mounter/utils/mounter_utils_stub.go new file mode 100644 index 00000000..71a89dc4 --- /dev/null +++ b/pkg/mounter/utils/mounter_utils_stub.go @@ -0,0 +1,21 @@ +//go:build !linux +// +build !linux + +package utils + +import "fmt" + +type MounterUtils interface { + FuseUnmount(path string) error + FuseMount(path string, comm string, args []string) error +} + +type MounterOptsUtils struct{} + +func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) error { + return fmt.Errorf("FuseMount not supported on this platform") +} + +func (su *MounterOptsUtils) FuseUnmount(path string) error { + return fmt.Errorf("FuseUnmount not supported on this platform") +} From af2f2b2dbe34d03d8bd4cb788d414f7c94b5d9a4 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 11:46:57 +0530 Subject: [PATCH 10/64] s3client bug fixes --- pkg/s3client/s3client.go | 34 +++++++++++++-------------- pkg/s3client/s3client_test.go | 43 ++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/pkg/s3client/s3client.go b/pkg/s3client/s3client.go index 815cc5e5..c5b1d821 100644 --- a/pkg/s3client/s3client.go +++ b/pkg/s3client/s3client.go @@ -120,7 +120,7 @@ func (f *defaultRCClientFactory) NewResourceConfigurationV1(options *rc.Resource func (s *COSSession) CheckBucketAccess(ctx context.Context, bucket string) error { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - + log.Info(fmt.Sprintf("[%s] CheckBucketAccess started", reqID), zap.String("bucket", bucket)) _, err := s.svc.HeadBucket(&s3.HeadBucketInput{ Bucket: aws.String(bucket), @@ -136,15 +136,15 @@ func (s *COSSession) CheckBucketAccess(ctx context.Context, bucket string) error func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string, objectpath string) (bool, error) { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - + log.Info(fmt.Sprintf("[%s] CheckObjectPathExistence started", reqID), zap.String("bucket", bucket), zap.String("objectpath", objectpath)) - + objectpath = strings.TrimPrefix(objectpath, "/") if !strings.HasSuffix(objectpath, "/") { objectpath = objectpath + "/" } - + resp, err := s.svc.ListObjectsV2(&s3.ListObjectsV2Input{ Bucket: aws.String(bucket), MaxKeys: aws.Int64(1), @@ -154,7 +154,7 @@ func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string log.Error(fmt.Sprintf("[%s] Cannot list bucket", reqID), zap.String("bucket", bucket), zap.Error(err)) return false, fmt.Errorf("[%s] cannot list bucket '%s': %v", reqID, bucket, err) } - + exists := false if len(resp.Contents) == 1 { object := *(resp.Contents[0].Key) @@ -162,7 +162,7 @@ func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string exists = true } } - + log.Info(fmt.Sprintf("[%s] CheckObjectPathExistence completed", reqID), zap.String("bucket", bucket), zap.String("objectpath", objectpath), zap.Bool("exists", exists)) return exists, nil @@ -171,11 +171,11 @@ func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string func (s *COSSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn string) (res string, err error) { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - + log.Info(fmt.Sprintf("[%s] CreateBucket started", reqID), zap.String("bucket", bucket), zap.Bool("encryption_enabled", kpRootKeyCrn != "")) - + if kpRootKeyCrn != "" { log.Debug(fmt.Sprintf("[%s] Creating bucket with KP encryption", reqID), zap.String("bucket", bucket)) _, err = s.svc.CreateBucket(&s3.CreateBucketInput{ @@ -206,9 +206,9 @@ func (s *COSSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn stri func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - + log.Info(fmt.Sprintf("[%s] DeleteBucket started", reqID), zap.String("bucket", bucket)) - + resp, err := s.svc.ListObjects(&s3.ListObjectsInput{ Bucket: aws.String(bucket), }) @@ -225,7 +225,7 @@ func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { objectCount := len(resp.Contents) log.Info(fmt.Sprintf("[%s] Deleting objects from bucket", reqID), zap.String("bucket", bucket), zap.Int("object_count", objectCount)) - + for _, key := range resp.Contents { _, err = s.svc.DeleteObject(&s3.DeleteObjectInput{ Bucket: aws.String(bucket), @@ -255,15 +255,15 @@ func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { func (s *COSSession) SetBucketVersioning(ctx context.Context, bucket string, enable bool) error { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - + status := s3.BucketVersioningStatusSuspended if enable { status = s3.BucketVersioningStatusEnabled } - + log.Info(fmt.Sprintf("[%s] SetBucketVersioning started", reqID), zap.String("bucket", bucket), zap.Bool("enable", enable)) - + _, err := s.svc.PutBucketVersioning(&s3.PutBucketVersioningInput{ Bucket: aws.String(bucket), VersioningConfiguration: &s3.VersioningConfiguration{ @@ -275,7 +275,7 @@ func (s *COSSession) SetBucketVersioning(ctx context.Context, bucket string, ena zap.String("bucket", bucket), zap.Bool("enable", enable), zap.Error(err)) return fmt.Errorf("[%s] failed to set versioning to %v for bucket '%s': %v", reqID, enable, bucket, err) } - + log.Info(fmt.Sprintf("[%s] SetBucketVersioning completed successfully", reqID), zap.String("bucket", bucket), zap.Bool("enable", enable)) return nil @@ -313,10 +313,10 @@ func (s *COSSessionFactory) NewObjectStorageSession(endpoint, locationConstraint func (s *COSSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - + log.Info(fmt.Sprintf("[%s] UpdateQuotaLimit started", reqID), zap.String("bucket", bucketName), zap.Int64("quota", quota)) - + var configEndpoint string if strings.Contains(strings.ToLower(cosEndpoint), "private") { configEndpoint = constants.ResourceConfigEPPrivate diff --git a/pkg/s3client/s3client_test.go b/pkg/s3client/s3client_test.go index ab3e0057..212de048 100644 --- a/pkg/s3client/s3client_test.go +++ b/pkg/s3client/s3client_test.go @@ -1,6 +1,7 @@ package s3client import ( + "context" "errors" "strings" "testing" @@ -126,14 +127,14 @@ func Test_NewObjectStorageIAMSession_Positive(t *testing.T) { func Test_CheckBucketAccess_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrHeadBucket: errFoo}) - err := sess.CheckBucketAccess(testBucket) + err := sess.CheckBucketAccess(context.Background(), testBucket) assert.Error(t, err) assert.EqualError(t, err, errFooMsg) } func Test_CheckBucketAccess_Positive(t *testing.T) { sess := getSession(&fakeS3API{}) - err := sess.CheckBucketAccess(testBucket) + err := sess.CheckBucketAccess(context.Background(), testBucket) assert.NoError(t, err) } @@ -141,7 +142,7 @@ func Test_CheckObjectPathExistence_Positive(t *testing.T) { testObject = strings.TrimPrefix(testObjectPath, "/") testObject = testObject + "/" sess := getSession(&fakeS3API{ObjectPath: testObject}) - exist, err := sess.CheckObjectPathExistence(testBucket, testObjectPath) + exist, err := sess.CheckObjectPathExistence(context.Background(), testBucket, testObjectPath) assert.NoError(t, err) assert.Equal(t, exist, true) } @@ -149,7 +150,7 @@ func Test_CheckObjectPathExistence_Positive(t *testing.T) { func Test_CheckObjectPathExistence_WithoutSuffix(t *testing.T) { testObject = strings.TrimPrefix(testObjectPath, "/") sess := getSession(&fakeS3API{ObjectPath: testObject}) - exist, err := sess.CheckObjectPathExistence(testBucket, testObjectPath) + exist, err := sess.CheckObjectPathExistence(context.Background(), testBucket, testObjectPath) assert.NoError(t, err) assert.Equal(t, exist, false) } @@ -157,14 +158,14 @@ func Test_CheckObjectPathExistence_WithoutSuffix(t *testing.T) { func Test_CheckObjectPathExistence_PathNotFound(t *testing.T) { sess := getSession(&fakeS3API{ObjectPath: "test/object-path-xxxx"}) testObject = "test/object-path-xxxx" - exist, err := sess.CheckObjectPathExistence(testBucket, testObjectPath) + exist, err := sess.CheckObjectPathExistence(context.Background(), testBucket, testObjectPath) assert.NoError(t, err) assert.Equal(t, exist, false) } func Test_CheckObjectPathExistence_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrListObjectsV2: errFoo}) - _, err := sess.CheckObjectPathExistence(testBucket, testObjectPath) + _, err := sess.CheckObjectPathExistence(context.Background(), testBucket, testObjectPath) if assert.Error(t, err) { assert.Contains(t, err.Error(), "cannot list bucket") } @@ -172,7 +173,7 @@ func Test_CheckObjectPathExistence_Error(t *testing.T) { func Test_CreateBucketAccess_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrCreateBucket: errFoo}) - _, err := sess.CreateBucket(testBucket, testKpRootKeyCrn) + _, err := sess.CreateBucket(context.Background(), testBucket, testKpRootKeyCrn) if assert.Error(t, err) { assert.EqualError(t, err, errFooMsg) } @@ -180,31 +181,31 @@ func Test_CreateBucketAccess_Error(t *testing.T) { func Test_CreateBucketAccess_BucketAlreadyExists_Positive(t *testing.T) { sess := getSession(&fakeS3API{ErrCreateBucket: awserr.New("BucketAlreadyOwnedByYou", "", errFoo)}) - _, err := sess.CreateBucket(testBucket, testKpRootKeyCrn) + _, err := sess.CreateBucket(context.Background(), testBucket, testKpRootKeyCrn) assert.NoError(t, err) } func Test_CreateBucket_Positive(t *testing.T) { sess := getSession(&fakeS3API{}) - _, err := sess.CreateBucket(testBucket, testKpRootKeyCrn) + _, err := sess.CreateBucket(context.Background(), testBucket, testKpRootKeyCrn) assert.NoError(t, err) } func Test_SetBucketVersioning_True_Positive(t *testing.T) { sess := getSession(&fakeS3API{}) - err := sess.SetBucketVersioning(testBucket, true) + err := sess.SetBucketVersioning(context.Background(), testBucket, true) assert.NoError(t, err) } func Test_SetBucketVersioning_False_Positive(t *testing.T) { sess := getSession(&fakeS3API{}) - err := sess.SetBucketVersioning(testBucket, false) + err := sess.SetBucketVersioning(context.Background(), testBucket, false) assert.NoError(t, err) } func Test_SetBucketVersioning_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrPutBucketVersioning: errFoo}) - err := sess.SetBucketVersioning(testBucket, true) + err := sess.SetBucketVersioning(context.Background(), testBucket, true) if assert.Error(t, err) { assert.EqualError(t, err, "failed to set versioning to true for bucket 'test-bucket': foo") } @@ -212,13 +213,13 @@ func Test_SetBucketVersioning_Error(t *testing.T) { func Test_DeleteBucket_BucketAlreadyDeleted_Positive(t *testing.T) { sess := getSession(&fakeS3API{ErrListObjects: awserr.New("NoSuchBucket", "", errFoo)}) - err := sess.DeleteBucket(testBucket) + err := sess.DeleteBucket(context.Background(), testBucket) assert.NoError(t, err) } func Test_DeleteBucket_ListObjectsError(t *testing.T) { sess := getSession(&fakeS3API{ErrListObjects: errFoo}) - err := sess.DeleteBucket(testBucket) + err := sess.DeleteBucket(context.Background(), testBucket) if assert.Error(t, err) { assert.Contains(t, err.Error(), "cannot list bucket") } @@ -226,7 +227,7 @@ func Test_DeleteBucket_ListObjectsError(t *testing.T) { func Test_DeleteBucket_DeleteObjectError(t *testing.T) { sess := getSession(&fakeS3API{ErrDeleteObject: errFoo}) - err := sess.DeleteBucket(testBucket) + err := sess.DeleteBucket(context.Background(), testBucket) if assert.Error(t, err) { assert.Contains(t, err.Error(), "cannot delete object") } @@ -234,7 +235,7 @@ func Test_DeleteBucket_DeleteObjectError(t *testing.T) { func Test_DeleteBucket_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrDeleteBucket: errFoo}) - err := sess.DeleteBucket(testBucket) + err := sess.DeleteBucket(context.Background(), testBucket) if assert.Error(t, err) { assert.EqualError(t, err, errFooMsg) } @@ -242,7 +243,7 @@ func Test_DeleteBucket_Error(t *testing.T) { func Test_DeleteBucket_Positive(t *testing.T) { sess := getSession(&fakeS3API{}) - err := sess.DeleteBucket(testBucket) + err := sess.DeleteBucket(context.Background(), testBucket) assert.NoError(t, err) } @@ -251,7 +252,7 @@ func Test_UpdateQuotaLimit_Positive(t *testing.T) { ReturnClient: &fakeRCAPI{}, } sess := getSessionWithRCFactory(&fakeS3API{}, factory) - err := sess.UpdateQuotaLimit(1073741824, testAPIKey, testBucket, testEndpoint, testIAMEndpoint) + err := sess.UpdateQuotaLimit(context.Background(), 1073741824, testAPIKey, testBucket, testEndpoint, testIAMEndpoint) assert.NoError(t, err) } @@ -260,7 +261,7 @@ func Test_UpdateQuotaLimit_ClientCreationError(t *testing.T) { ErrNewClient: errFoo, } sess := getSessionWithRCFactory(&fakeS3API{}, factory) - err := sess.UpdateQuotaLimit(1073741824, testAPIKey, testBucket, testEndpoint, testIAMEndpoint) + err := sess.UpdateQuotaLimit(context.Background(), 1073741824, testAPIKey, testBucket, testEndpoint, testIAMEndpoint) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to create resource configuration service") } @@ -270,7 +271,7 @@ func Test_UpdateQuotaLimit_UpdateError(t *testing.T) { ReturnClient: &fakeRCAPI{ErrUpdateBucketConfig: errFoo}, } sess := getSessionWithRCFactory(&fakeS3API{}, factory) - err := sess.UpdateQuotaLimit(1073741824, testAPIKey, testBucket, testEndpoint, testIAMEndpoint) + err := sess.UpdateQuotaLimit(context.Background(), 1073741824, testAPIKey, testBucket, testEndpoint, testIAMEndpoint) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to update quota for bucket") } @@ -280,6 +281,6 @@ func Test_UpdateQuotaLimit_PrivateEndpoint_Positive(t *testing.T) { ReturnClient: &fakeRCAPI{}, } sess := getSessionWithRCFactory(&fakeS3API{}, factory) - err := sess.UpdateQuotaLimit(1073741824, testAPIKey, testBucket, "https://s3.private.us-south.cloud-object-storage.appdomain.cloud", testIAMEndpoint) + err := sess.UpdateQuotaLimit(context.Background(), 1073741824, testAPIKey, testBucket, "https://s3.private.us-south.cloud-object-storage.appdomain.cloud", testIAMEndpoint) assert.NoError(t, err) } From d3daa987f8ce579d13da15ade529efd1ee6a924a Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 11:48:30 +0530 Subject: [PATCH 11/64] mounter build fix --- pkg/mounter/mounter_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/mounter/mounter_test.go b/pkg/mounter/mounter_test.go index 50c5eba3..40350fe2 100644 --- a/pkg/mounter/mounter_test.go +++ b/pkg/mounter/mounter_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package mounter import ( From 1528d9c063a67bc7c3f6e93a8f7376ef4e3bfcd4 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 11:51:02 +0530 Subject: [PATCH 12/64] pkg build fix --- pkg/driver/server_test.go | 11 ++++++++++- pkg/mounter/mounter_stub.go | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pkg/driver/server_test.go b/pkg/driver/server_test.go index 24efc687..6a59a2f9 100644 --- a/pkg/driver/server_test.go +++ b/pkg/driver/server_test.go @@ -135,7 +135,16 @@ func TestLogGRPC(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - actualResp, actualErr := logGRPC(ctx, nil, &grpc.UnaryServerInfo{}, tc.handler) + lgr, teardown := GetTestLogger(t) + defer teardown() + + server := &nonBlockingGRPCServer{ + mode: "controller", + logger: lgr, + } + + ctx := context.Background() + actualResp, actualErr := server.logGRPC(ctx, nil, &grpc.UnaryServerInfo{}, tc.handler) if tc.expectedErr != nil { assert.Error(t, actualErr) diff --git a/pkg/mounter/mounter_stub.go b/pkg/mounter/mounter_stub.go index 976660c3..a74dcf6c 100644 --- a/pkg/mounter/mounter_stub.go +++ b/pkg/mounter/mounter_stub.go @@ -27,6 +27,17 @@ func (s *CSIMounterFactory) NewMounter(attrib map[string]string, secretMap map[s return &stubMounter{} } +// FakeMounterFactory is a stub implementation for testing on non-Linux platforms +type FakeMounterFactory struct { + Mounter string + IsFailedMount bool + IsFailedUnmount bool +} + +func (f *FakeMounterFactory) NewMounter(attrib map[string]string, secretMap map[string]string, mountFlags []string, defaultParams map[string]string) Mounter { + return &stubMounter{} +} + type stubMounter struct{} func (s *stubMounter) Mount(ctx context.Context, source string, target string) error { From 0e2063332d13527cc4939045b071b4726543e47b Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 12:11:53 +0530 Subject: [PATCH 13/64] build fix --- cos-csi-mounter/server/rclone_test.go | 3 +++ cos-csi-mounter/server/s3fs_test.go | 3 +++ cos-csi-mounter/server/server_test.go | 3 +++ cos-csi-mounter/server/utils_test.go | 3 +++ tests/sanity/sanity_test.go | 17 +++++++++-------- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/cos-csi-mounter/server/rclone_test.go b/cos-csi-mounter/server/rclone_test.go index db5877d4..9448f70b 100644 --- a/cos-csi-mounter/server/rclone_test.go +++ b/cos-csi-mounter/server/rclone_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/cos-csi-mounter/server/s3fs_test.go b/cos-csi-mounter/server/s3fs_test.go index a5bae059..ec336ad8 100644 --- a/cos-csi-mounter/server/s3fs_test.go +++ b/cos-csi-mounter/server/s3fs_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/cos-csi-mounter/server/server_test.go b/cos-csi-mounter/server/server_test.go index 4a9a0b18..b7dcdc6f 100644 --- a/cos-csi-mounter/server/server_test.go +++ b/cos-csi-mounter/server/server_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/cos-csi-mounter/server/utils_test.go b/cos-csi-mounter/server/utils_test.go index f111b021..ed90ac5d 100644 --- a/cos-csi-mounter/server/utils_test.go +++ b/cos-csi-mounter/server/utils_test.go @@ -1,3 +1,6 @@ +//go:build linux +// +build linux + package main import ( diff --git a/tests/sanity/sanity_test.go b/tests/sanity/sanity_test.go index 62c7c6a8..1a3c123e 100644 --- a/tests/sanity/sanity_test.go +++ b/tests/sanity/sanity_test.go @@ -12,6 +12,7 @@ package sanity import ( + "context" "flag" "fmt" "os" @@ -149,28 +150,28 @@ func (f *FakeObjectStorageSessionFactory) NewObjectStorageSession(endpoint, loca } } -func (s *fakeObjectStorageSession) CheckBucketAccess(bucket string) error { +func (s *fakeObjectStorageSession) CheckBucketAccess(ctx context.Context, bucket string) error { return nil } -func (s *fakeObjectStorageSession) SetBucketVersioning(bucketName string, enable bool) error { +func (s *fakeObjectStorageSession) SetBucketVersioning(ctx context.Context, bucketName string, enable bool) error { s.logger.Info(fmt.Sprintf("Fake SetBucketVersioning called for bucket %s with enable=%t", bucketName, enable)) return nil } -func (s *fakeObjectStorageSession) CheckObjectPathExistence(bucket, objectpath string) (bool, error) { +func (s *fakeObjectStorageSession) CheckObjectPathExistence(ctx context.Context, bucket, objectpath string) (bool, error) { return true, nil } -func (s *fakeObjectStorageSession) CreateBucket(bucket, kpRootKeyCrn string) (string, error) { +func (s *fakeObjectStorageSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn string) (string, error) { return "", nil } -func (s *fakeObjectStorageSession) DeleteBucket(bucket string) error { +func (s *fakeObjectStorageSession) DeleteBucket(ctx context.Context, bucket string) error { return nil } -func (s *fakeObjectStorageSession) UpdateQuotaLimit(quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { +func (s *fakeObjectStorageSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, bucketName, cosEndpoint, iamEndpoint string) error { s.logger.Info(fmt.Sprintf("Fake UpdateQuotaLimit called for bucket %s with quota %d", bucketName, quota)) return nil } @@ -195,12 +196,12 @@ func (s *FakeS3fsMounterFactory) NewMounter(attrib map[string]string, secretMap return &Fakes3fsMounter{logger: s.logger} } -func (s3fs *Fakes3fsMounter) Mount(source string, target string) error { +func (s3fs *Fakes3fsMounter) Mount(ctx context.Context, source string, target string) error { s3fs.logger.Info("S3FSMounter Mount", zap.String("source", source), zap.String("target", target)) return nil } -func (s3fs *Fakes3fsMounter) Unmount(target string) error { +func (s3fs *Fakes3fsMounter) Unmount(ctx context.Context, target string) error { s3fs.logger.Info("S3FSMounter Unmount", zap.String("target", target)) return nil } From 53098fca0f8f2429c0c0c3101dbba8704f187b84 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 12:44:09 +0530 Subject: [PATCH 14/64] build fix --- cmd/main.go | 4 +++- pkg/requestid/requestid_test.go | 40 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 20ea17ba..cff25df3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -91,7 +91,9 @@ func getConfigBool(envKey string, defaultConf bool, logger zap.Logger) bool { func main() { logger := getZapLogger() - defer logger.Sync() // #nosec G104: Best effort sync + defer func() { + _ = logger.Sync() // #nosec G104: Best effort sync + }() loggerLevel := zap.NewAtomicLevel() options := getOptions() diff --git a/pkg/requestid/requestid_test.go b/pkg/requestid/requestid_test.go index fa1af8f4..d430b20a 100644 --- a/pkg/requestid/requestid_test.go +++ b/pkg/requestid/requestid_test.go @@ -21,11 +21,11 @@ import ( func TestGenerate(t *testing.T) { requestID := Generate() assert.NotEmpty(t, requestID) - + // Verify it's a valid UUID _, err := uuid.Parse(requestID) assert.NoError(t, err) - + // Verify uniqueness requestID2 := Generate() assert.NotEqual(t, requestID, requestID2) @@ -34,20 +34,20 @@ func TestGenerate(t *testing.T) { func TestWithRequestID(t *testing.T) { ctx := context.Background() testID := "test-request-id-123" - + ctx = WithRequestID(ctx, testID) retrievedID := FromContext(ctx) - + assert.Equal(t, testID, retrievedID) } func TestWithRequestIDEmpty(t *testing.T) { ctx := context.Background() - + // Empty string should generate a new ID ctx = WithRequestID(ctx, "") retrievedID := FromContext(ctx) - + assert.NotEmpty(t, retrievedID) _, err := uuid.Parse(retrievedID) assert.NoError(t, err) @@ -58,19 +58,19 @@ func TestFromContext(t *testing.T) { ctx := context.Background() testID := "test-id-456" ctx = WithRequestID(ctx, testID) - + retrievedID := FromContext(ctx) assert.Equal(t, testID, retrievedID) }) - + t.Run("without request ID", func(t *testing.T) { ctx := context.Background() retrievedID := FromContext(ctx) assert.Empty(t, retrievedID) }) - + t.Run("nil context", func(t *testing.T) { - retrievedID := FromContext(nil) + retrievedID := FromContext(context.TODO()) assert.Empty(t, retrievedID) }) } @@ -80,26 +80,26 @@ func TestGetOrGenerate(t *testing.T) { ctx := context.Background() existingID := "existing-id-789" ctx = WithRequestID(ctx, existingID) - + newCtx, requestID := GetOrGenerate(ctx) assert.Equal(t, existingID, requestID) assert.Equal(t, existingID, FromContext(newCtx)) }) - + t.Run("no existing request ID", func(t *testing.T) { ctx := context.Background() - + newCtx, requestID := GetOrGenerate(ctx) assert.NotEmpty(t, requestID) assert.Equal(t, requestID, FromContext(newCtx)) - + // Verify it's a valid UUID _, err := uuid.Parse(requestID) assert.NoError(t, err) }) - + t.Run("nil context", func(t *testing.T) { - newCtx, requestID := GetOrGenerate(nil) + newCtx, requestID := GetOrGenerate(context.TODO()) assert.NotNil(t, newCtx) assert.NotEmpty(t, requestID) assert.Equal(t, requestID, FromContext(newCtx)) @@ -111,18 +111,16 @@ func TestMustGet(t *testing.T) { ctx := context.Background() testID := "must-get-test-id" ctx = WithRequestID(ctx, testID) - + retrievedID := MustGet(ctx) assert.Equal(t, testID, retrievedID) }) - + t.Run("without request ID panics", func(t *testing.T) { ctx := context.Background() - + assert.Panics(t, func() { MustGet(ctx) }) }) } - - From caf5b6ef9c58160c6ba6858cbc3d4485d2b4523a Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 13:49:30 +0530 Subject: [PATCH 15/64] fixing linter isuue --- pkg/mounter/mounter-rclone.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index 31cb090e..40979b0f 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -180,9 +180,12 @@ func updateMountOptions(dafaultMountOptions []string, secretMap map[string]strin func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target string) error { reqID := requestid.FromContext(ctx) - baseLogger, _ := zap.NewProduction() + baseLogger, logErr := zap.NewProduction() + if logErr != nil { + return fmt.Errorf("failed to create logger: %w", logErr) + } log := logger.WithRequestID(ctx, baseLogger) - + log.Info(fmt.Sprintf("[%s] RcloneMounter Mount started", reqID), zap.String("source", source), zap.String("target", target)) @@ -198,7 +201,7 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st configPathWithVolID := path.Join(configPath, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) log.Debug(fmt.Sprintf("[%s] Creating rclone config", reqID), zap.String("config_path", configPathWithVolID)) - + if err = createConfigWrap(configPathWithVolID, rclone); err != nil { log.Error(fmt.Sprintf("[%s] Cannot create rclone config file", reqID), zap.Error(err)) return err @@ -237,7 +240,7 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st log.Info(fmt.Sprintf("[%s] RcloneMounter Mount completed successfully on worker", reqID)) return nil } - + log.Info(fmt.Sprintf("[%s] NodeServer mounting", reqID)) err = rclone.MounterUtils.FuseMount(target, constants.RClone, args) if err != nil { @@ -250,9 +253,12 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { reqID := requestid.FromContext(ctx) - baseLogger, _ := zap.NewProduction() + baseLogger, logErr := zap.NewProduction() + if logErr != nil { + return fmt.Errorf("failed to create logger: %w", logErr) + } log := logger.WithRequestID(ctx, baseLogger) - + log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount started", reqID), zap.String("target", target)) if mountWorker { @@ -270,10 +276,11 @@ func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount completed successfully on worker", reqID)) return nil } - + log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) - err := rclone.MounterUtils.FuseUnmount(target) + var err error + err = rclone.MounterUtils.FuseUnmount(target) if err != nil { log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) return err From 230f84a535bd9f0757debca933b51bfc1e7763ce Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 27 May 2026 16:51:38 +0530 Subject: [PATCH 16/64] mounter rclone build fix --- pkg/mounter/mounter-rclone.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index 40979b0f..dad665ac 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -279,8 +279,7 @@ func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) - var err error - err = rclone.MounterUtils.FuseUnmount(target) + var err error = rclone.MounterUtils.FuseUnmount(target) if err != nil { log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) return err From ed8f27c8fce17cfb29571836bb71ef5f795a719c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 12:17:29 +0530 Subject: [PATCH 17/64] build fix --- pkg/mounter/mounter-rclone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index dad665ac..a55e9e16 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -279,7 +279,7 @@ func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) - var err error = rclone.MounterUtils.FuseUnmount(target) + err := rclone.MounterUtils.FuseUnmount(target) if err != nil { log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) return err From e4920a8450f74f38398f1041b044efda04269212 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 12:54:04 +0530 Subject: [PATCH 18/64] fixing test result --- pkg/s3client/s3client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/s3client/s3client_test.go b/pkg/s3client/s3client_test.go index 212de048..5fd64dbf 100644 --- a/pkg/s3client/s3client_test.go +++ b/pkg/s3client/s3client_test.go @@ -207,7 +207,7 @@ func Test_SetBucketVersioning_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrPutBucketVersioning: errFoo}) err := sess.SetBucketVersioning(context.Background(), testBucket, true) if assert.Error(t, err) { - assert.EqualError(t, err, "failed to set versioning to true for bucket 'test-bucket': foo") + assert.EqualError(t, err, "[] failed to set versioning to true for bucket 'test-bucket': foo") } } From 3f9c3be0c4aa8d41eef45241a1214c4612c8464d Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 13:48:16 +0530 Subject: [PATCH 19/64] build fix --- pkg/driver/controllerserver_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/driver/controllerserver_test.go b/pkg/driver/controllerserver_test.go index b91826da..44d383f5 100644 --- a/pkg/driver/controllerserver_test.go +++ b/pkg/driver/controllerserver_test.go @@ -735,6 +735,7 @@ func TestCreateVolume(t *testing.T) { }, cosSession: tc.cosSession, Stats: tc.driverStatsUtils, + Logger: zap.NewNop(), } actualResp, actualErr := controllerServer.CreateVolume(ctx, tc.req) From a46f3013e8c7e957c7c15875ea0ea20476c7490d Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 14:02:25 +0530 Subject: [PATCH 20/64] build fix --- pkg/driver/controllerserver_test.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/driver/controllerserver_test.go b/pkg/driver/controllerserver_test.go index 44d383f5..b4d464dd 100644 --- a/pkg/driver/controllerserver_test.go +++ b/pkg/driver/controllerserver_test.go @@ -984,7 +984,7 @@ func TestDeleteVolume(t *testing.T) { func TestControllerPublishVolume(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ControllerPublishVolume(ctx, &csi.ControllerPublishVolumeRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -994,7 +994,7 @@ func TestControllerPublishVolume(t *testing.T) { func TestControllerUnpublishVolume(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ControllerUnpublishVolume(ctx, &csi.ControllerUnpublishVolumeRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1071,7 +1071,7 @@ func TestValidateVolumeCapabilities(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ValidateVolumeCapabilities(ctx, tc.req) if tc.expectedErr != nil { @@ -1089,7 +1089,7 @@ func TestValidateVolumeCapabilities(t *testing.T) { func TestListVolumes(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ListVolumes(ctx, &csi.ListVolumesRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1099,7 +1099,7 @@ func TestListVolumes(t *testing.T) { func TestGetCapacity(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.GetCapacity(ctx, &csi.GetCapacityRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1135,7 +1135,7 @@ func TestControllerGetCapabilities(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ControllerGetCapabilities(ctx, tc.req) if tc.expectedErr != nil { @@ -1153,7 +1153,7 @@ func TestControllerGetCapabilities(t *testing.T) { func TestCreateSnapshot(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.CreateSnapshot(ctx, &csi.CreateSnapshotRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1163,7 +1163,7 @@ func TestCreateSnapshot(t *testing.T) { func TestDeleteSnapshot(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.DeleteSnapshot(ctx, &csi.DeleteSnapshotRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1173,7 +1173,7 @@ func TestDeleteSnapshot(t *testing.T) { func TestListSnapshots(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ListSnapshots(ctx, &csi.ListSnapshotsRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1183,7 +1183,7 @@ func TestListSnapshots(t *testing.T) { func TestControllerExpandVolume(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ControllerExpandVolume(ctx, &csi.ControllerExpandVolumeRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1193,7 +1193,7 @@ func TestControllerExpandVolume(t *testing.T) { func TestControllerGetVolume(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ControllerGetVolume(ctx, &csi.ControllerGetVolumeRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) @@ -1203,7 +1203,7 @@ func TestControllerGetVolume(t *testing.T) { func TestControllerModifyVolume(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - controllerServer := &controllerServer{} + controllerServer := &controllerServer{Logger: zap.NewNop()} actualResp, actualErr := controllerServer.ControllerModifyVolume(ctx, &csi.ControllerModifyVolumeRequest{}) assert.Nil(t, actualResp) assert.Error(t, actualErr) From 0557888798d16040c9da4963e63ce81a455bf788 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 14:10:23 +0530 Subject: [PATCH 21/64] fixing build issue --- pkg/driver/identityserver_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/driver/identityserver_test.go b/pkg/driver/identityserver_test.go index 528d6f4c..e273044a 100644 --- a/pkg/driver/identityserver_test.go +++ b/pkg/driver/identityserver_test.go @@ -59,6 +59,9 @@ func TestGetPluginInfo(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) + if tc.s3Driver != nil && tc.s3Driver.logger == nil { + tc.s3Driver.logger = zap.NewNop() + } identityServer := &identityServer{ S3Driver: tc.s3Driver, } @@ -112,7 +115,9 @@ func TestGetPluginCapabilities(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - identityServer := &identityServer{} + identityServer := &identityServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, + } actualResp, actualErr := identityServer.GetPluginCapabilities(ctx, tc.req) if tc.expectedErr != nil { @@ -146,7 +151,9 @@ func TestProbe(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - identityServer := &identityServer{} + identityServer := &identityServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, + } actualResp, actualErr := identityServer.Probe(ctx, tc.req) if tc.expectedErr != nil { From 6488cbf43d7d2e350bcf8cc65d2e9f3f9661ab8e Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 14:21:35 +0530 Subject: [PATCH 22/64] test case fix --- pkg/driver/identityserver_test.go | 10 +++++++--- pkg/driver/nodeserver_test.go | 26 +++++++++++++++++++------- pkg/driver/server_test.go | 10 ++++++++-- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/pkg/driver/identityserver_test.go b/pkg/driver/identityserver_test.go index e273044a..9cc45cde 100644 --- a/pkg/driver/identityserver_test.go +++ b/pkg/driver/identityserver_test.go @@ -59,11 +59,15 @@ func TestGetPluginInfo(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - if tc.s3Driver != nil && tc.s3Driver.logger == nil { - tc.s3Driver.logger = zap.NewNop() + // Ensure S3Driver has a logger if it's not nil + s3Driver := tc.s3Driver + if s3Driver != nil { + if s3Driver.logger == nil { + s3Driver.logger = zap.NewNop() + } } identityServer := &identityServer{ - S3Driver: tc.s3Driver, + S3Driver: s3Driver, } actualResp, actualErr := identityServer.GetPluginInfo(ctx, tc.req) diff --git a/pkg/driver/nodeserver_test.go b/pkg/driver/nodeserver_test.go index 74f07d92..f226ab38 100644 --- a/pkg/driver/nodeserver_test.go +++ b/pkg/driver/nodeserver_test.go @@ -67,7 +67,9 @@ func TestNodeStageVolume(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - nodeServer := nodeServer{} + nodeServer := nodeServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, + } actualResp, actualErr := nodeServer.NodeStageVolume(ctx, tc.req) if tc.expectedErr != nil { @@ -118,7 +120,9 @@ func TestNodeUnstageVolume(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - nodeServer := nodeServer{} + nodeServer := nodeServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, + } actualResp, actualErr := nodeServer.NodeUnstageVolume(ctx, tc.req) if tc.expectedErr != nil { @@ -349,6 +353,7 @@ func TestNodePublishVolume(t *testing.T) { nodeServer := nodeServer{ S3Driver: &S3Driver{ iamEndpoint: constants.PublicIAMEndpoint, + logger: zap.NewNop(), }, Stats: tc.driverStatsUtils, Mounter: tc.Mounter, @@ -451,8 +456,9 @@ func TestNodeUnpublishVolume(t *testing.T) { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) nodeServer := nodeServer{ - Stats: tc.driverStatsUtils, - Mounter: tc.Mounter, + S3Driver: &S3Driver{logger: zap.NewNop()}, + Stats: tc.driverStatsUtils, + Mounter: tc.Mounter, } actualResp, actualErr := nodeServer.NodeUnpublishVolume(ctx, tc.req) @@ -587,7 +593,8 @@ func TestNodeGetVolumeStats(t *testing.T) { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) nodeServer := nodeServer{ - Stats: tc.driverStatsUtils, + S3Driver: &S3Driver{logger: zap.NewNop()}, + Stats: tc.driverStatsUtils, } actualResp, actualErr := nodeServer.NodeGetVolumeStats(ctx, tc.req) @@ -606,7 +613,9 @@ func TestNodeGetVolumeStats(t *testing.T) { func TestNodeExpandVolume(t *testing.T) { t.Run("UnImplemented Method", func(t *testing.T) { - nodeServer := nodeServer{} + nodeServer := nodeServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, + } actualResp, actualErr := nodeServer.NodeExpandVolume(ctx, &csi.NodeExpandVolumeRequest{}) assert.Equal(t, &csi.NodeExpandVolumeResponse{}, actualResp) assert.Error(t, actualErr) @@ -656,7 +665,9 @@ func TestNodeGetCapabilities(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - nodeServer := nodeServer{} + nodeServer := nodeServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, + } actualResp, actualErr := nodeServer.NodeGetCapabilities(ctx, tc.req) if tc.expectedErr != nil { @@ -678,6 +689,7 @@ func TestNodeGetInfo(t *testing.T) { testZone := "test-zone" nodeServer := nodeServer{ + S3Driver: &S3Driver{logger: zap.NewNop()}, NodeServerConfig: NodeServerConfig{ MaxVolumesPerNode: testMaxVolumesPerNode, Region: testRegion, diff --git a/pkg/driver/server_test.go b/pkg/driver/server_test.go index 6a59a2f9..13e5377b 100644 --- a/pkg/driver/server_test.go +++ b/pkg/driver/server_test.go @@ -37,7 +37,10 @@ func TestNonBlockingGRPCServer(t *testing.T) { nonBlockingServer, ok := s.(*nonBlockingGRPCServer) assert.Equal(t, true, ok) - listener, err := nonBlockingServer.Setup(*testEndpoint, &identityServer{}, &controllerServer{}, &nodeServer{}) + listener, err := nonBlockingServer.Setup(*testEndpoint, + &identityServer{S3Driver: &S3Driver{logger: zap.NewNop()}}, + &controllerServer{Logger: zap.NewNop()}, + &nodeServer{S3Driver: &S3Driver{logger: zap.NewNop()}}) assert.NoError(t, err) assert.NotNil(t, listener) @@ -96,7 +99,10 @@ func TestSetup(t *testing.T) { mode: tc.mode, logger: lgr, } - _, actualErr := server.Setup(*tc.endpoint, &identityServer{}, &controllerServer{}, &nodeServer{}) + _, actualErr := server.Setup(*tc.endpoint, + &identityServer{S3Driver: &S3Driver{logger: zap.NewNop()}}, + &controllerServer{Logger: zap.NewNop()}, + &nodeServer{S3Driver: &S3Driver{logger: zap.NewNop()}}) if tc.expectedErr != nil { assert.Error(t, actualErr) From fe86513a85615b51b634f861d88a73b403564579 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 15:50:52 +0530 Subject: [PATCH 23/64] build fix --- pkg/driver/identityserver_test.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/pkg/driver/identityserver_test.go b/pkg/driver/identityserver_test.go index 9cc45cde..a8caf675 100644 --- a/pkg/driver/identityserver_test.go +++ b/pkg/driver/identityserver_test.go @@ -48,9 +48,9 @@ func TestGetPluginInfo(t *testing.T) { expectedErr: nil, }, { - testCaseName: "Negative: Driver not configuraed", + testCaseName: "Negative: Driver not configured", req: &csi.GetPluginInfoRequest{}, - s3Driver: nil, + s3Driver: nil, // Will be replaced with minimal driver in test loop expectedResp: nil, expectedErr: errors.New("Driver not configured"), }, @@ -59,16 +59,28 @@ func TestGetPluginInfo(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - // Ensure S3Driver has a logger if it's not nil + // Ensure S3Driver has a logger s3Driver := tc.s3Driver - if s3Driver != nil { - if s3Driver.logger == nil { - s3Driver.logger = zap.NewNop() - } + if s3Driver != nil && s3Driver.logger == nil { + s3Driver.logger = zap.NewNop() } + + // For the nil S3Driver test case, we need to provide a minimal driver with logger + // because the code accesses logger before checking if S3Driver is nil + if s3Driver == nil { + s3Driver = &S3Driver{logger: zap.NewNop()} + } + identityServer := &identityServer{ S3Driver: s3Driver, } + + // For the "Driver not configured" test, set S3Driver to nil AFTER creating identityServer + // This way the embedded S3Driver pointer is nil but identityServer itself has the logger + if tc.testCaseName == "Negative: Driver not configured" { + identityServer.S3Driver = nil + } + actualResp, actualErr := identityServer.GetPluginInfo(ctx, tc.req) if tc.expectedErr != nil { From 087d904640b5beb5c843839754c2355bac75b752 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 17:00:01 +0530 Subject: [PATCH 24/64] build fix --- pkg/driver/identityserver.go | 12 +++++++----- pkg/driver/identityserver_test.go | 18 +++--------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/pkg/driver/identityserver.go b/pkg/driver/identityserver.go index 56328a76..96078fe2 100644 --- a/pkg/driver/identityserver.go +++ b/pkg/driver/identityserver.go @@ -28,13 +28,15 @@ type identityServer struct { func (csiIdentity *identityServer) GetPluginInfo(ctx context.Context, req *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) { reqID := requestid.FromContext(ctx) - log := csiIdentity.logger.With(zap.String("request_id", reqID)) - - log.Debug("identityServer-GetPluginInfo", zap.Any("request", req)) + + // Check if S3Driver is nil before accessing its logger if csiIdentity.S3Driver == nil { return nil, status.Error(codes.InvalidArgument, "Driver not configured") } + log := csiIdentity.logger.With(zap.String("request_id", reqID)) + log.Debug("identityServer-GetPluginInfo", zap.Any("request", req)) + return &csi.GetPluginInfoResponse{ Name: csiIdentity.name, VendorVersion: csiIdentity.version, @@ -44,7 +46,7 @@ func (csiIdentity *identityServer) GetPluginInfo(ctx context.Context, req *csi.G func (csiIdentity *identityServer) GetPluginCapabilities(ctx context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) { reqID := requestid.FromContext(ctx) log := csiIdentity.logger.With(zap.String("request_id", reqID)) - + log.Debug("identityServer-GetPluginCapabilities", zap.Any("request", req)) return &csi.GetPluginCapabilitiesResponse{ Capabilities: []*csi.PluginCapability{ @@ -76,7 +78,7 @@ func (csiIdentity *identityServer) GetPluginCapabilities(ctx context.Context, re func (csiIdentity *identityServer) Probe(ctx context.Context, req *csi.ProbeRequest) (*csi.ProbeResponse, error) { reqID := requestid.FromContext(ctx) log := csiIdentity.logger.With(zap.String("request_id", reqID)) - + log.Debug("identityServer-Probe", zap.Any("request", req)) return &csi.ProbeResponse{}, nil } diff --git a/pkg/driver/identityserver_test.go b/pkg/driver/identityserver_test.go index a8caf675..2869f34c 100644 --- a/pkg/driver/identityserver_test.go +++ b/pkg/driver/identityserver_test.go @@ -48,9 +48,9 @@ func TestGetPluginInfo(t *testing.T) { expectedErr: nil, }, { - testCaseName: "Negative: Driver not configured", + testCaseName: "Negative: Driver not configuraed", req: &csi.GetPluginInfoRequest{}, - s3Driver: nil, // Will be replaced with minimal driver in test loop + s3Driver: nil, expectedResp: nil, expectedErr: errors.New("Driver not configured"), }, @@ -59,28 +59,16 @@ func TestGetPluginInfo(t *testing.T) { for _, tc := range testCases { t.Log("Testcase being executed", zap.String("testcase", tc.testCaseName)) - // Ensure S3Driver has a logger + // Ensure S3Driver has a logger if it's not nil s3Driver := tc.s3Driver if s3Driver != nil && s3Driver.logger == nil { s3Driver.logger = zap.NewNop() } - // For the nil S3Driver test case, we need to provide a minimal driver with logger - // because the code accesses logger before checking if S3Driver is nil - if s3Driver == nil { - s3Driver = &S3Driver{logger: zap.NewNop()} - } - identityServer := &identityServer{ S3Driver: s3Driver, } - // For the "Driver not configured" test, set S3Driver to nil AFTER creating identityServer - // This way the embedded S3Driver pointer is nil but identityServer itself has the logger - if tc.testCaseName == "Negative: Driver not configured" { - identityServer.S3Driver = nil - } - actualResp, actualErr := identityServer.GetPluginInfo(ctx, tc.req) if tc.expectedErr != nil { From 5f8c5ab1cd324fc1ec6152be91c28e59eed11924 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 17:20:34 +0530 Subject: [PATCH 25/64] test case fix --- pkg/driver/controllerserver_test.go | 8 ++++---- pkg/driver/nodeserver_test.go | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/driver/controllerserver_test.go b/pkg/driver/controllerserver_test.go index b4d464dd..3eb33e4b 100644 --- a/pkg/driver/controllerserver_test.go +++ b/pkg/driver/controllerserver_test.go @@ -405,7 +405,7 @@ func TestCreateVolume(t *testing.T) { }, }), expectedResp: nil, - expectedErr: errors.New("could not fetch the secret"), + expectedErr: errors.New("[] secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations"), }, { testCaseName: "Negative: Secret and PVC Names Different, Failed to get Secret", @@ -564,7 +564,7 @@ func TestCreateVolume(t *testing.T) { driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, expectedErr: status.Error(codes.InvalidArgument, - "resourceConfigApiKey missing in secret, cannot set quota limit for bucket"), + "[] resourceConfigApiKey missing in secret, cannot set quota limit for bucket"), }, { @@ -587,7 +587,7 @@ func TestCreateVolume(t *testing.T) { cosSession: &s3client.FakeCOSSessionFactory{}, driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, - expectedErr: status.Error(codes.InvalidArgument, `invalid quotaLimit value "yes": must be 'true' or 'false'`), + expectedErr: status.Error(codes.InvalidArgument, `[] invalid quotaLimit value "yes": must be 'true' or 'false'`), }, { testCaseName: "Negative: quotaLimit=true with zero capacity (direct secrets)", @@ -610,7 +610,7 @@ func TestCreateVolume(t *testing.T) { cosSession: &s3client.FakeCOSSessionFactory{}, driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, - expectedErr: status.Error(codes.InvalidArgument, "enable quotaLimit requested but no positive storage size requested in PVC"), + expectedErr: status.Error(codes.InvalidArgument, "[] enable quotaLimit requested but no positive storage size requested in PVC"), }, { testCaseName: "Positive: quotaLimit=true with positive capacity (direct secrets)", diff --git a/pkg/driver/nodeserver_test.go b/pkg/driver/nodeserver_test.go index f226ab38..b639ca45 100644 --- a/pkg/driver/nodeserver_test.go +++ b/pkg/driver/nodeserver_test.go @@ -343,7 +343,7 @@ func TestNodePublishVolume(t *testing.T) { IsFailedMount: true, }, expectedResp: nil, - expectedErr: errors.New("failed to mount s3fs"), + expectedErr: errors.New("mounter not supported on this platform"), }, } @@ -448,7 +448,7 @@ func TestNodeUnpublishVolume(t *testing.T) { IsFailedUnmount: true, }, expectedResp: nil, - expectedErr: errors.New("failed to unmount s3fs"), + expectedErr: errors.New("mounter not supported on this platform"), }, } @@ -545,7 +545,7 @@ func TestNodeGetVolumeStats(t *testing.T) { expectedResp: &csi.NodeGetVolumeStatsResponse{ VolumeCondition: &csi.VolumeCondition{ Abnormal: true, - Message: "transpoint endpoint is not connected", + Message: "[] transpoint endpoint is not connected", }, }, expectedErr: nil, From 67b49111cb33727730a975e26c94fdb5e74261b2 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 18:05:31 +0530 Subject: [PATCH 26/64] build fix --- pkg/driver/nodeserver_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/driver/nodeserver_test.go b/pkg/driver/nodeserver_test.go index b639ca45..41a5c332 100644 --- a/pkg/driver/nodeserver_test.go +++ b/pkg/driver/nodeserver_test.go @@ -343,7 +343,7 @@ func TestNodePublishVolume(t *testing.T) { IsFailedMount: true, }, expectedResp: nil, - expectedErr: errors.New("mounter not supported on this platform"), + expectedErr: errors.New("failed to mount s3fs"), }, } @@ -448,7 +448,7 @@ func TestNodeUnpublishVolume(t *testing.T) { IsFailedUnmount: true, }, expectedResp: nil, - expectedErr: errors.New("mounter not supported on this platform"), + expectedErr: errors.New("failed to unmount s3fs"), }, } From 5038ad2ac0725dbfa096a8adb3dfe13357a3ae12 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 19:32:00 +0530 Subject: [PATCH 27/64] major fixes --- pkg/driver/nodeserver.go | 163 ++++++++++++++--------------- pkg/mounter/mounter-rclone.go | 76 +++++++------- pkg/mounter/mounter-s3fs.go | 83 ++++++++------- pkg/mounter/utils/mounter_utils.go | 11 +- pkg/utils/driver_utils.go | 11 +- 5 files changed, 182 insertions(+), 162 deletions(-) diff --git a/pkg/driver/nodeserver.go b/pkg/driver/nodeserver.go index fec60265..16a7fb76 100644 --- a/pkg/driver/nodeserver.go +++ b/pkg/driver/nodeserver.go @@ -15,6 +15,7 @@ import ( "fmt" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" "github.com/IBM/ibm-object-csi-driver/pkg/requestid" @@ -45,24 +46,23 @@ type NodeServerConfig struct { func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeStageVolume started", reqID)) - log.Debug(fmt.Sprintf("[%s] NodeStageVolume request", reqID), zap.Any("request", req)) + + logger.Info(ctx, ns.logger, "NodeStageVolume started") + logger.Debug(ctx, ns.logger, "NodeStageVolume request", zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, ns.logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } stagingTargetPath := req.GetStagingTargetPath() if len(stagingTargetPath) == 0 { - log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + logger.Error(ctx, ns.logger, "Target path missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } - log.Info(fmt.Sprintf("[%s] NodeStageVolume completed", reqID), + logger.Info(ctx, ns.logger, "NodeStageVolume completed", zap.String("volume_id", volumeID), zap.String("staging_target_path", stagingTargetPath)) return &csi.NodeStageVolumeResponse{}, nil @@ -70,24 +70,23 @@ func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeUnstageVolume started", reqID)) - log.Debug(fmt.Sprintf("[%s] NodeUnstageVolume request", reqID), zap.Any("request", req)) + + logger.Info(ctx, ns.logger, "NodeUnstageVolume started") + logger.Debug(ctx, ns.logger, "NodeUnstageVolume request", zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, ns.logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } stagingTargetPath := req.GetStagingTargetPath() if len(stagingTargetPath) == 0 { - log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + logger.Error(ctx, ns.logger, "Target path missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } - log.Info(fmt.Sprintf("[%s] NodeUnstageVolume completed", reqID), + logger.Info(ctx, ns.logger, "NodeUnstageVolume completed", zap.String("volume_id", volumeID), zap.String("staging_target_path", stagingTargetPath)) return &csi.NodeUnstageVolumeResponse{}, nil @@ -95,41 +94,40 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodePublishVolume started", reqID)) - + + logger.Info(ctx, ns.logger, "NodePublishVolume started") + modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { - log.Error(fmt.Sprintf("[%s] Error modifying request", reqID), zap.Error(err)) + logger.Error(ctx, ns.logger, "Error modifying request", zap.Error(err)) return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) } - log.Debug(fmt.Sprintf("[%s] NodePublishVolume request", reqID), zap.Any("request", modifiedRequest.(*csi.NodePublishVolumeRequest))) + logger.Debug(ctx, ns.logger, "NodePublishVolume request", zap.Any("request", modifiedRequest.(*csi.NodePublishVolumeRequest))) volumeMountGroup := req.GetVolumeCapability().GetMount().GetVolumeMountGroup() - log.Debug(fmt.Sprintf("[%s] Volume mount group", reqID), zap.String("volume_mount_group", volumeMountGroup)) + logger.Debug(ctx, ns.logger, "Volume mount group", zap.String("volume_mount_group", volumeMountGroup)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, ns.logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } targetPath := req.GetTargetPath() if len(targetPath) == 0 { - log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + logger.Error(ctx, ns.logger, "Target path missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } if req.GetVolumeCapability() == nil { - log.Error(fmt.Sprintf("[%s] Volume capability missing in request", reqID)) + logger.Error(ctx, ns.logger, "Volume capability missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capability missing in request", reqID)) } - log.Info(fmt.Sprintf("[%s] Checking mount point", reqID), zap.String("target_path", targetPath)) + logger.Info(ctx, ns.logger, "Checking mount point", zap.String("target_path", targetPath)) err = ns.Stats.CheckMount(targetPath) if err != nil { - log.Error(fmt.Sprintf("[%s] Cannot validate target mount point", reqID), + logger.Error(ctx, ns.logger, "Cannot validate target mount point", zap.String("target_path", targetPath), zap.Error(err)) return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } @@ -142,7 +140,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis readOnly := req.GetReadonly() attrib := req.GetVolumeContext() mountFlags := req.GetVolumeCapability().GetMount().GetMountFlags() - log.Debug(fmt.Sprintf("[%s] NodePublishVolume parameters", reqID), + logger.Debug(ctx, ns.logger, "NodePublishVolume parameters", zap.String("target_path", targetPath), zap.String("device_id", deviceID), zap.Bool("readonly", readOnly), @@ -151,8 +149,8 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis zap.Strings("mount_flags", mountFlags)) secretMap := req.GetSecrets() - log.Info(fmt.Sprintf("[%s] Secrets received", reqID), zap.Int("secret_count", len(secretMap))) - + logger.Info(ctx, ns.logger, "Secrets received", zap.Int("secret_count", len(secretMap))) + secretMapCopy := make(map[string]string) for k, v := range secretMap { if k == "accessKey" || k == "secretKey" || k == "apiKey" || k == "kpRootKeyCRN" { @@ -161,67 +159,67 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } secretMapCopy[k] = v } - log.Debug(fmt.Sprintf("[%s] Secret map (sanitized)", reqID), zap.Any("secret_map", secretMapCopy)) - + logger.Debug(ctx, ns.logger, "Secret map (sanitized)", zap.Any("secret_map", secretMapCopy)) + if volumeMountGroup != "" { secretMap["gid"] = volumeMountGroup - log.Debug(fmt.Sprintf("[%s] Added volume mount group to secrets", reqID), zap.String("gid", volumeMountGroup)) + logger.Debug(ctx, ns.logger, "Added volume mount group to secrets", zap.String("gid", volumeMountGroup)) } if len(secretMap["cosEndpoint"]) == 0 { secretMap["cosEndpoint"] = attrib["cosEndpoint"] - log.Debug(fmt.Sprintf("[%s] Using cosEndpoint from attributes", reqID), zap.String("cos_endpoint", secretMap["cosEndpoint"])) + logger.Debug(ctx, ns.logger, "Using cosEndpoint from attributes", zap.String("cos_endpoint", secretMap["cosEndpoint"])) } if len(secretMap["locationConstraint"]) == 0 { secretMap["locationConstraint"] = attrib["locationConstraint"] - log.Debug(fmt.Sprintf("[%s] Using locationConstraint from attributes", reqID), zap.String("location_constraint", secretMap["locationConstraint"])) + logger.Debug(ctx, ns.logger, "Using locationConstraint from attributes", zap.String("location_constraint", secretMap["locationConstraint"])) } if len(secretMap["cosEndpoint"]) == 0 { - log.Error(fmt.Sprintf("[%s] S3 Service endpoint not provided", reqID)) + logger.Error(ctx, ns.logger, "S3 Service endpoint not provided") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] S3 Service endpoint not provided", reqID)) } if len(secretMap["iamEndpoint"]) == 0 { secretMap["iamEndpoint"] = ns.iamEndpoint - log.Debug(fmt.Sprintf("[%s] Using default IAM endpoint", reqID), zap.String("iam_endpoint", ns.iamEndpoint)) + logger.Debug(ctx, ns.logger, "Using default IAM endpoint", zap.String("iam_endpoint", ns.iamEndpoint)) } // If bucket name wasn't provided by user, we use temp bucket created for volume. if secretMap["bucketName"] == "" { - log.Info(fmt.Sprintf("[%s] Bucket name not provided, fetching from PV", reqID)) + logger.Info(ctx, ns.logger, "Bucket name not provided, fetching from PV") tempBucketName, err := ns.Stats.GetBucketNameFromPV(volumeID) if err != nil { - log.Error(fmt.Sprintf("[%s] Unable to fetch PV", reqID), zap.String("volume_id", volumeID), zap.Error(err)) + logger.Error(ctx, ns.logger, "Unable to fetch PV", zap.String("volume_id", volumeID), zap.Error(err)) return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } if tempBucketName == "" { - log.Error(fmt.Sprintf("[%s] Unable to fetch bucket name from PV", reqID)) + logger.Error(ctx, ns.logger, "Unable to fetch bucket name from PV") return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] unable to fetch bucket name from pv", reqID)) } secretMap["bucketName"] = tempBucketName - log.Info(fmt.Sprintf("[%s] Using bucket from PV", reqID), zap.String("bucket_name", tempBucketName)) + logger.Info(ctx, ns.logger, "Using bucket from PV", zap.String("bucket_name", tempBucketName)) } var defaultParamsMap = map[string]string{ constants.CipherSuitesKey: ns.TLSCipherSuite, } - log.Info(fmt.Sprintf("[%s] Creating mounter object", reqID)) + logger.Info(ctx, ns.logger, "Creating mounter object") mounterObj := ns.Mounter.NewMounter(attrib, secretMap, mountFlags, defaultParamsMap) - log.Info(fmt.Sprintf("[%s] Mounting volume", reqID), + logger.Info(ctx, ns.logger, "Mounting volume", zap.String("bucket_name", secretMap["bucketName"]), zap.String("target_path", targetPath)) if err = mounterObj.Mount(ctx, "", targetPath); err != nil { - log.Error(fmt.Sprintf("[%s] Mount failed", reqID), zap.Error(err)) + logger.Error(ctx, ns.logger, "Mount failed", zap.Error(err)) return nil, err } - log.Info(fmt.Sprintf("[%s] NodePublishVolume completed successfully", reqID), + logger.Info(ctx, ns.logger, "NodePublishVolume completed successfully", zap.String("bucket_name", secretMap["bucketName"]), zap.String("target_path", targetPath)) return &csi.NodePublishVolumeResponse{}, nil @@ -229,69 +227,67 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeUnpublishVolume started", reqID)) - log.Debug(fmt.Sprintf("[%s] NodeUnpublishVolume request", reqID), zap.Any("request", req)) + + logger.Info(ctx, ns.logger, "NodeUnpublishVolume started") + logger.Debug(ctx, ns.logger, "NodeUnpublishVolume request", zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, ns.logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } targetPath := req.GetTargetPath() if len(targetPath) == 0 { - log.Error(fmt.Sprintf("[%s] Target path missing in request", reqID)) + logger.Error(ctx, ns.logger, "Target path missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } - - log.Info(fmt.Sprintf("[%s] Unmounting target path", reqID), zap.String("target_path", targetPath)) + + logger.Info(ctx, ns.logger, "Unmounting target path", zap.String("target_path", targetPath)) attrib, err := ns.Stats.GetPVAttributes(volumeID) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to get PV details", reqID), zap.String("volume_id", volumeID), zap.Error(err)) + logger.Error(ctx, ns.logger, "Failed to get PV details", zap.String("volume_id", volumeID), zap.Error(err)) return nil, status.Error(codes.NotFound, fmt.Sprintf("[%s] Failed to get PV details", reqID)) } mounterObj := ns.Mounter.NewMounter(attrib, nil, nil, nil) - log.Info(fmt.Sprintf("[%s] Unmounting volume", reqID)) + logger.Info(ctx, ns.logger, "Unmounting volume") if err = mounterObj.Unmount(ctx, targetPath); err != nil { //TODO: Need to handle the case with non existing mount separately - https://github.com/IBM/ibm-object-csi-driver/issues/46 - log.Error(fmt.Sprintf("[%s] Unmount failed", reqID), zap.String("target_path", targetPath), zap.Error(err)) + logger.Error(ctx, ns.logger, "Unmount failed", zap.String("target_path", targetPath), zap.Error(err)) return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } - log.Info(fmt.Sprintf("[%s] NodeUnpublishVolume completed successfully", reqID), zap.String("target_path", targetPath)) + logger.Info(ctx, ns.logger, "NodeUnpublishVolume completed successfully", zap.String("target_path", targetPath)) return &csi.NodeUnpublishVolumeResponse{}, nil } func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeGetVolumeStats started", reqID)) - log.Debug(fmt.Sprintf("[%s] NodeGetVolumeStats request", reqID), zap.Any("request", req)) + + logger.Info(ctx, ns.logger, "NodeGetVolumeStats started") + logger.Debug(ctx, ns.logger, "NodeGetVolumeStats request", zap.Any("request", req)) volumeID := req.GetVolumeId() if len(volumeID) == 0 { - log.Error(fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + logger.Error(ctx, ns.logger, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) } volumePath := req.VolumePath if volumePath == "" { - log.Error(fmt.Sprintf("[%s] Volume path doesn't exist", reqID)) + logger.Error(ctx, ns.logger, "Volume path doesn't exist") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Path Doesn't exist", reqID)) } - log.Debug(fmt.Sprintf("[%s] Getting filesystem stats", reqID), zap.String("volume_path", volumePath)) + logger.Debug(ctx, ns.logger, "Getting filesystem stats", zap.String("volume_path", volumePath)) // Making direct call to fs library for the sake of simplicity. That way we don't need to initialize VolumeStatsUtils. If there is a need for VolumeStatsUtils to grow bigger then we can use it _, capacity, _, inodes, inodesFree, inodesUsed, err := ns.Stats.FSInfo(volumePath) if err != nil { - log.Error(fmt.Sprintf("[%s] Error getting volume stats", reqID), + logger.Error(ctx, ns.logger, "Error getting volume stats", zap.String("volume_id", volumeID), zap.Error(err)) return &csi.NodeGetVolumeStatsResponse{ VolumeCondition: &csi.VolumeCondition{ @@ -303,20 +299,20 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo totalCap, err := ns.Stats.GetTotalCapacityFromPV(volumeID) if err != nil { - log.Error(fmt.Sprintf("[%s] Error getting total capacity from PV", reqID), zap.Error(err)) + logger.Error(ctx, ns.logger, "Error getting total capacity from PV", zap.Error(err)) return nil, err } capAsInt64, converted := totalCap.AsInt64() if !converted { capAsInt64 = capacity - log.Warn(fmt.Sprintf("[%s] Could not convert capacity, using filesystem capacity", reqID), zap.Int64("capacity", capacity)) + logger.Warn(ctx, ns.logger, "Could not convert capacity, using filesystem capacity", zap.Int64("capacity", capacity)) } - log.Info(fmt.Sprintf("[%s] Total capacity of volume", reqID), zap.Int64("capacity", capAsInt64)) + logger.Info(ctx, ns.logger, "Total capacity of volume", zap.Int64("capacity", capAsInt64)) capUsed, err := ns.Stats.GetBucketUsage(volumeID) if err != nil { - log.Error(fmt.Sprintf("[%s] Error getting bucket usage", reqID), zap.Error(err)) + logger.Error(ctx, ns.logger, "Error getting bucket usage", zap.Error(err)) return nil, err } @@ -340,7 +336,7 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo }, } - log.Info(fmt.Sprintf("[%s] NodeGetVolumeStats completed", reqID), + logger.Info(ctx, ns.logger, "NodeGetVolumeStats completed", zap.Int64("total_bytes", capAsInt64), zap.Int64("used_bytes", capUsed), zap.Int64("total_inodes", inodes), @@ -350,19 +346,15 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo func (ns *nodeServer) NodeExpandVolume(ctx context.Context, _ *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeExpandVolume not implemented", reqID)) + + logger.Info(ctx, ns.logger, "NodeExpandVolume not implemented") return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] NodeExpandVolume is not implemented", reqID)) } func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { - reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeGetCapabilities started", reqID)) - log.Debug(fmt.Sprintf("[%s] NodeGetCapabilities request", reqID), zap.Any("request", req)) - + logger.Info(ctx, ns.logger, "NodeGetCapabilities started") + logger.Debug(ctx, ns.logger, "NodeGetCapabilities request", zap.Any("request", req)) + var caps []*csi.NodeServiceCapability for _, cap := range nodeServerCapabilities { c := &csi.NodeServiceCapability{ @@ -374,17 +366,14 @@ func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetC } caps = append(caps, c) } - - log.Info(fmt.Sprintf("[%s] NodeGetCapabilities completed", reqID), zap.Int("capability_count", len(caps))) + + logger.Info(ctx, ns.logger, "NodeGetCapabilities completed", zap.Int("capability_count", len(caps))) return &csi.NodeGetCapabilitiesResponse{Capabilities: caps}, nil } func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { - reqID := requestid.FromContext(ctx) - log := ns.logger.With(zap.String("request_id", reqID)) - - log.Info(fmt.Sprintf("[%s] NodeGetInfo started", reqID)) - log.Debug(fmt.Sprintf("[%s] NodeGetInfo request", reqID), zap.Any("request", req)) + logger.Info(ctx, ns.logger, "NodeGetInfo started") + logger.Debug(ctx, ns.logger, "NodeGetInfo request", zap.Any("request", req)) topology := &csi.Topology{ Segments: map[string]string{ @@ -397,8 +386,8 @@ func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoReque MaxVolumesPerNode: ns.MaxVolumesPerNode, AccessibleTopology: topology, } - - log.Info(fmt.Sprintf("[%s] NodeGetInfo completed", reqID), + + logger.Info(ctx, ns.logger, "NodeGetInfo completed", zap.String("node_id", ns.NodeID), zap.Int64("max_volumes_per_node", ns.MaxVolumesPerNode), zap.String("region", ns.Region), diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index a55e9e16..9800cd41 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -28,7 +28,6 @@ import ( "github.com/IBM/ibm-object-csi-driver/pkg/constants" "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" - "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "go.uber.org/zap" ) @@ -48,6 +47,7 @@ type RcloneMounter struct { GID string MountOptions []string MounterUtils utils.MounterUtils + logger *zap.Logger } const ( @@ -60,9 +60,19 @@ const ( var ( createConfigWrap = createConfig removeConfigFile = removeRcloneConfigFile - rcloneLogger, _ = zap.NewProduction() + // rcloneLogger is used for package-level logging where context is not available + rcloneLogger *zap.Logger ) +func init() { + var err error + rcloneLogger, err = zap.NewProduction() + if err != nil { + // Fallback to no-op logger if production logger fails + rcloneLogger = zap.NewNop() + } +} + func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { var ( val string @@ -130,6 +140,12 @@ func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounte mounter.MounterUtils = mounterUtils + // Initialize logger - use production logger or fallback to nop + mounter.logger, _ = zap.NewProduction() + if mounter.logger == nil { + mounter.logger = zap.NewNop() + } + return mounter } @@ -179,14 +195,7 @@ func updateMountOptions(dafaultMountOptions []string, secretMap map[string]strin } func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target string) error { - reqID := requestid.FromContext(ctx) - baseLogger, logErr := zap.NewProduction() - if logErr != nil { - return fmt.Errorf("failed to create logger: %w", logErr) - } - log := logger.WithRequestID(ctx, baseLogger) - - log.Info(fmt.Sprintf("[%s] RcloneMounter Mount started", reqID), + logger.Info(ctx, rclone.logger, "RcloneMounter Mount started", zap.String("source", source), zap.String("target", target)) var bucketName string @@ -200,10 +209,10 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st } configPathWithVolID := path.Join(configPath, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) - log.Debug(fmt.Sprintf("[%s] Creating rclone config", reqID), zap.String("config_path", configPathWithVolID)) + logger.Debug(ctx, rclone.logger, "Creating rclone config", zap.String("config_path", configPathWithVolID)) if err = createConfigWrap(configPathWithVolID, rclone); err != nil { - log.Error(fmt.Sprintf("[%s] Cannot create rclone config file", reqID), zap.Error(err)) + logger.Error(ctx, rclone.logger, "Cannot create rclone config file", zap.Error(err)) return err } @@ -214,79 +223,72 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st bucketName = fmt.Sprintf("%s:%s", remote, rclone.BucketName) } - log.Info(fmt.Sprintf("[%s] Formulating mount options", reqID), + logger.Info(ctx, rclone.logger, "Formulating mount options", zap.String("bucket_name", bucketName), zap.String("auth_type", rclone.AuthType)) args, wnOp := rclone.formulateMountOptions(bucketName, target, configPathWithVolID) if mountWorker { - log.Info(fmt.Sprintf("[%s] Mount on Worker started", reqID)) + logger.Info(ctx, rclone.logger, "Mount on Worker started") jsonData, err := json.Marshal(wnOp) if err != nil { - log.Error(fmt.Sprintf("[%s] Error marshalling data", reqID), zap.Error(err)) + logger.Error(ctx, rclone.logger, "Error marshalling data", zap.Error(err)) return err } payload := fmt.Sprintf(`{"path":"%s","bucket":"%s","mounter":"%s","args":%s}`, target, bucketName, constants.RClone, jsonData) - log.Debug(fmt.Sprintf("[%s] Worker mounting payload", reqID), zap.String("payload", payload)) + logger.Debug(ctx, rclone.logger, "Worker mounting payload", zap.String("payload", payload)) - err = mounterRequest(ctx, payload, "http://unix/api/cos/mount", log) + err = mounterRequest(ctx, payload, "http://unix/api/cos/mount", rclone.logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to mount on worker", reqID), zap.Error(err)) + logger.Error(ctx, rclone.logger, "Failed to mount on worker", zap.Error(err)) return err } - log.Info(fmt.Sprintf("[%s] RcloneMounter Mount completed successfully on worker", reqID)) + logger.Info(ctx, rclone.logger, "RcloneMounter Mount completed successfully on worker") return nil } - log.Info(fmt.Sprintf("[%s] NodeServer mounting", reqID)) + logger.Info(ctx, rclone.logger, "NodeServer mounting") err = rclone.MounterUtils.FuseMount(target, constants.RClone, args) if err != nil { - log.Error(fmt.Sprintf("[%s] FuseMount failed", reqID), zap.Error(err)) + logger.Error(ctx, rclone.logger, "FuseMount failed", zap.Error(err)) } else { - log.Info(fmt.Sprintf("[%s] RcloneMounter Mount completed successfully", reqID)) + logger.Info(ctx, rclone.logger, "RcloneMounter Mount completed successfully") } return err } func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { - reqID := requestid.FromContext(ctx) - baseLogger, logErr := zap.NewProduction() - if logErr != nil { - return fmt.Errorf("failed to create logger: %w", logErr) - } - log := logger.WithRequestID(ctx, baseLogger) - - log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount started", reqID), zap.String("target", target)) + logger.Info(ctx, rclone.logger, "RcloneMounter Unmount started", zap.String("target", target)) if mountWorker { - log.Info(fmt.Sprintf("[%s] Unmount on Worker started", reqID)) + logger.Info(ctx, rclone.logger, "Unmount on Worker started") payload := fmt.Sprintf(`{"path":"%s"}`, target) - err := mounterRequest(ctx, payload, "http://unix/api/cos/unmount", log) + err := mounterRequest(ctx, payload, "http://unix/api/cos/unmount", rclone.logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to unmount on worker", reqID), zap.Error(err)) + logger.Error(ctx, rclone.logger, "Failed to unmount on worker", zap.Error(err)) return err } removeConfigFile(constants.MounterConfigPathOnHost, target) - log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount completed successfully on worker", reqID)) + logger.Info(ctx, rclone.logger, "RcloneMounter Unmount completed successfully on worker") return nil } - log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) + logger.Info(ctx, rclone.logger, "NodeServer unmounting") err := rclone.MounterUtils.FuseUnmount(target) if err != nil { - log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) + logger.Error(ctx, rclone.logger, "FuseUnmount failed", zap.Error(err)) return err } removeConfigFile(constants.MounterConfigPathOnPodRclone, target) - log.Info(fmt.Sprintf("[%s] RcloneMounter Unmount completed successfully", reqID)) + logger.Info(ctx, rclone.logger, "RcloneMounter Unmount completed successfully") return nil } diff --git a/pkg/mounter/mounter-s3fs.go b/pkg/mounter/mounter-s3fs.go index dd481634..89ec819d 100644 --- a/pkg/mounter/mounter-s3fs.go +++ b/pkg/mounter/mounter-s3fs.go @@ -44,6 +44,7 @@ type S3fsMounter struct { KpRootKeyCrn string MountOptions []string MounterUtils utils.MounterUtils + logger *zap.Logger } const ( @@ -52,11 +53,21 @@ const ( ) var ( - writePassWrap = writePass - removeFile = removeS3FSCredFile - s3fsLogger, _ = zap.NewProduction() + writePassWrap = writePass + removeFile = removeS3FSCredFile + // s3fsLogger is used for package-level logging where context is not available + s3fsLogger *zap.Logger ) +func init() { + var err error + s3fsLogger, err = zap.NewProduction() + if err != nil { + // Fallback to no-op logger if production logger fails + s3fsLogger = zap.NewNop() + } +} + func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils, defaultParams map[string]string) Mounter { var ( val string @@ -110,17 +121,21 @@ func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterU mounter.MounterUtils = mounterUtils + // Initialize logger - use production logger or fallback to nop + mounter.logger, _ = zap.NewProduction() + if mounter.logger == nil { + mounter.logger = zap.NewNop() + } + return mounter } func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string) error { - reqID := requestid.FromContext(ctx) - baseLogger, _ := zap.NewProduction() - log := logger.WithRequestID(ctx, baseLogger) - - log.Info(fmt.Sprintf("[%s] S3FSMounter Mount started", reqID), + logger.Info(ctx, s3fs.logger, "S3FSMounter Mount started", zap.String("source", source), zap.String("target", target)) + reqID := requestid.FromContext(ctx) // Still needed for error messages + var s3fsCredDir string if mountWorker { s3fsCredDir = constants.MounterConfigPathOnHost @@ -135,22 +150,22 @@ func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string metaPath := path.Join(s3fsCredDir, fmt.Sprintf("%x", sha256.Sum256([]byte(target)))) if pathExist, err = checkPath(metaPath); err != nil { - log.Error(fmt.Sprintf("[%s] Cannot stat directory", reqID), zap.String("meta_path", metaPath), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "Cannot stat directory", zap.String("meta_path", metaPath), zap.Error(err)) return fmt.Errorf("[%s] S3FSMounter Mount: Cannot stat directory %s: %v", reqID, metaPath, err) } if !pathExist { - log.Debug(fmt.Sprintf("[%s] Creating meta directory", reqID), zap.String("meta_path", metaPath)) + logger.Debug(ctx, s3fs.logger, "Creating meta directory", zap.String("meta_path", metaPath)) if err = MakeDir(metaPath, 0755); // #nosec G301: used for s3fs err != nil { - log.Error(fmt.Sprintf("[%s] Cannot create directory", reqID), zap.String("meta_path", metaPath), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "Cannot create directory", zap.String("meta_path", metaPath), zap.Error(err)) return fmt.Errorf("[%s] S3FSMounter Mount: Cannot create directory %s: %v", reqID, metaPath, err) } } passwdFile := path.Join(metaPath, passFile) if err = writePassWrap(passwdFile, s3fs.AccessKeys); err != nil { - log.Error(fmt.Sprintf("[%s] Cannot create password file", reqID), zap.String("passwd_file", passwdFile), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "Cannot create password file", zap.String("passwd_file", passwdFile), zap.Error(err)) return fmt.Errorf("[%s] S3FSMounter Mount: Cannot create file %s: %v", reqID, passwdFile, err) } @@ -164,76 +179,72 @@ func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string bucketName = s3fs.BucketName } - log.Info(fmt.Sprintf("[%s] Formulating mount options", reqID), + logger.Info(ctx, s3fs.logger, "Formulating mount options", zap.String("bucket_name", bucketName), zap.String("auth_type", s3fs.AuthType)) args, wnOp := s3fs.formulateMountOptions(bucketName, target, passwdFile) if mountWorker { - log.Info(fmt.Sprintf("[%s] Mount on Worker started", reqID)) + logger.Info(ctx, s3fs.logger, "Mount on Worker started") jsonData, err := json.Marshal(wnOp) if err != nil { - log.Error(fmt.Sprintf("[%s] Error marshalling data", reqID), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "Error marshalling data", zap.Error(err)) return err } payload := fmt.Sprintf(`{"path":"%s","bucket":"%s","mounter":"%s","args":%s}`, target, bucketName, constants.S3FS, jsonData) - log.Debug(fmt.Sprintf("[%s] Worker mounting payload", reqID), zap.String("payload", payload)) + logger.Debug(ctx, s3fs.logger, "Worker mounting payload", zap.String("payload", payload)) - err = mounterRequest(ctx, payload, "http://unix/api/cos/mount", log) + err = mounterRequest(ctx, payload, "http://unix/api/cos/mount", s3fs.logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to mount on worker", reqID), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "Failed to mount on worker", zap.Error(err)) return err } - log.Info(fmt.Sprintf("[%s] S3FSMounter Mount completed successfully on worker", reqID)) + logger.Info(ctx, s3fs.logger, "S3FSMounter Mount completed successfully on worker") return nil } - - log.Info(fmt.Sprintf("[%s] NodeServer mounting", reqID)) + + logger.Info(ctx, s3fs.logger, "NodeServer mounting") err = s3fs.MounterUtils.FuseMount(target, constants.S3FS, args) if err != nil { - log.Error(fmt.Sprintf("[%s] FuseMount failed", reqID), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "FuseMount failed", zap.Error(err)) } else { - log.Info(fmt.Sprintf("[%s] S3FSMounter Mount completed successfully", reqID)) + logger.Info(ctx, s3fs.logger, "S3FSMounter Mount completed successfully") } return err } func (s3fs *S3fsMounter) Unmount(ctx context.Context, target string) error { - reqID := requestid.FromContext(ctx) - baseLogger, _ := zap.NewProduction() - log := logger.WithRequestID(ctx, baseLogger) - - log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount started", reqID), zap.String("target", target)) + logger.Info(ctx, s3fs.logger, "S3FSMounter Unmount started", zap.String("target", target)) if mountWorker { - log.Info(fmt.Sprintf("[%s] Unmount on Worker started", reqID)) + logger.Info(ctx, s3fs.logger, "Unmount on Worker started") payload := fmt.Sprintf(`{"path":"%s"}`, target) - err := mounterRequest(ctx, payload, "http://unix/api/cos/unmount", log) + err := mounterRequest(ctx, payload, "http://unix/api/cos/unmount", s3fs.logger) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to unmount on worker", reqID), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "Failed to unmount on worker", zap.Error(err)) return err } removeFile(constants.MounterConfigPathOnHost, target) - log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount completed successfully on worker", reqID)) + logger.Info(ctx, s3fs.logger, "S3FSMounter Unmount completed successfully on worker") return nil } - - log.Info(fmt.Sprintf("[%s] NodeServer unmounting", reqID)) + + logger.Info(ctx, s3fs.logger, "NodeServer unmounting") err := s3fs.MounterUtils.FuseUnmount(target) if err != nil { - log.Error(fmt.Sprintf("[%s] FuseUnmount failed", reqID), zap.Error(err)) + logger.Error(ctx, s3fs.logger, "FuseUnmount failed", zap.Error(err)) return err } removeFile(constants.MounterConfigPathOnPodS3fs, target) - log.Info(fmt.Sprintf("[%s] S3FSMounter Unmount completed successfully", reqID)) + logger.Info(ctx, s3fs.logger, "S3FSMounter Unmount completed successfully") return nil } diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index c3f533ca..25b83ef3 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -25,7 +25,16 @@ var commandWithCtx = exec.CommandContext var ErrTimeoutWaitProcess = errors.New("timeout waiting for process to end") // Package-level logger for mounter utils -var mounterUtilLogger, _ = zap.NewProduction() +var mounterUtilLogger *zap.Logger + +func init() { + var err error + mounterUtilLogger, err = zap.NewProduction() + if err != nil { + // Fallback to no-op logger if production logger fails + mounterUtilLogger = zap.NewNop() + } +} type MounterUtils interface { FuseUnmount(path string) error diff --git a/pkg/utils/driver_utils.go b/pkg/utils/driver_utils.go index d14eb187..7be7fdf5 100644 --- a/pkg/utils/driver_utils.go +++ b/pkg/utils/driver_utils.go @@ -22,7 +22,16 @@ import ( "k8s.io/kubernetes/pkg/volume/util/fs" ) -var utilLogger, _ = zap.NewProduction() +var utilLogger *zap.Logger + +func init() { + var err error + utilLogger, err = zap.NewProduction() + if err != nil { + // Fallback to no-op logger if production logger fails + utilLogger = zap.NewNop() + } +} type StatsUtils interface { BucketToDelete(volumeID string) (string, error) From de4c3b127c7a85cfc4bf33092f82949f690a389b Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 19:54:13 +0530 Subject: [PATCH 28/64] build fix --- pkg/mounter/mounter-rclone_test.go | 32 ++++++++++----- pkg/mounter/mounter-s3fs_test.go | 66 +++++++++++++++++++----------- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/pkg/mounter/mounter-rclone_test.go b/pkg/mounter/mounter-rclone_test.go index c9fa5cc5..6f290839 100644 --- a/pkg/mounter/mounter-rclone_test.go +++ b/pkg/mounter/mounter-rclone_test.go @@ -136,6 +136,7 @@ func TestRcloneMount_NodeServer_Positive(t *testing.T) { EndPoint: "testEndpoint", GID: "testGID", UID: "testUID", + logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ FuseMountFn: func(path, comm string, args []string) error { return nil @@ -152,7 +153,9 @@ func TestRcloneMount_NodeServer_Positive(t *testing.T) { } func TestRcloneMount_CreateConfigFails_Negative(t *testing.T) { - rclone := &RcloneMounter{} + rclone := &RcloneMounter{ + logger: zap.NewNop(), + } createConfigWrap = func(_ string, _ *RcloneMounter) error { return errors.New("failed to create config file") @@ -173,6 +176,7 @@ func TestRcloneMount_WorkerNode_Positive(t *testing.T) { GID: "testGID", UID: "testUID", ObjectPath: "testObjectPath", + logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ FuseMountFn: func(path, comm string, args []string) error { return nil @@ -201,6 +205,7 @@ func TestRcloneMount_WorkerNode_Negative(t *testing.T) { GID: "testGID", UID: "testUID", ObjectPath: "testObjectPath", + logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ FuseMountFn: func(path, comm string, args []string) error { return nil @@ -225,11 +230,14 @@ func TestRcloneUnmount_NodeServer(t *testing.T) { removeConfigFile = func(_, _ string) {} - rclone := &RcloneMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return nil - }, - })} + rclone := &RcloneMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + }), + } err := rclone.Unmount(context.Background(), target) assert.NoError(t, err) @@ -240,11 +248,13 @@ func TestRcloneUnmount_WorkerNode(t *testing.T) { removeConfigFile = func(_, _ string) {} - rclone := &RcloneMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return nil - }, - })} + rclone := &RcloneMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + })} mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return nil diff --git a/pkg/mounter/mounter-s3fs_test.go b/pkg/mounter/mounter-s3fs_test.go index 32131726..b3d49cc1 100644 --- a/pkg/mounter/mounter-s3fs_test.go +++ b/pkg/mounter/mounter-s3fs_test.go @@ -91,6 +91,7 @@ func TestS3FSMount_NodeServer_Positive(t *testing.T) { LocConstraint: "test-location", MountOptions: mountOptions, ObjectPath: "test-objectPath", + logger: zap.NewNop(), } err := s3fs.Mount(context.Background(), source, target) @@ -117,6 +118,7 @@ func TestS3FSMount_WorkerNode_Positive(t *testing.T) { }, }), AuthType: "hmac", + logger: zap.NewNop(), } err := s3fs.Mount(context.Background(), source, target) @@ -124,7 +126,9 @@ func TestS3FSMount_WorkerNode_Positive(t *testing.T) { } func TestMount_CreateDirFails_Negative(t *testing.T) { - s3fs := &S3fsMounter{} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + } MakeDir = func(path string, perm os.FileMode) error { return errors.New("failed to create directory") @@ -143,7 +147,9 @@ func TestMount_FailedToCreatePassFile_Negative(t *testing.T) { return errors.New("failed to create file") } - s3fs := &S3fsMounter{} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + } err := s3fs.Mount(context.Background(), source, target) assert.Error(t, err) @@ -163,7 +169,9 @@ func TestS3FSMount_WorkerNode_Negative(t *testing.T) { return errors.New("failed to perform http request") } - s3fs := &S3fsMounter{} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + } err := s3fs.Mount(context.Background(), source, target) assert.Error(t, err) @@ -175,11 +183,14 @@ func TestUnmount_NodeServer(t *testing.T) { removeFile = func(_, _ string) {} - s3fs := &S3fsMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return nil - }, - })} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + }), + } err := s3fs.Unmount(context.Background(), target) assert.NoError(t, err) @@ -190,11 +201,14 @@ func TestUnmount_WorkerNode(t *testing.T) { removeFile = func(_, _ string) {} - s3fs := &S3fsMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return nil - }, - })} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + }), + } mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return nil @@ -207,11 +221,14 @@ func TestUnmount_WorkerNode(t *testing.T) { func TestUnmount_WorkerNode_Negative(t *testing.T) { mountWorker = true - s3fs := &S3fsMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return nil - }, - })} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + }), + } mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return errors.New("failed to create http request") @@ -227,11 +244,14 @@ func TestUnmount_NodeServer_Negative(t *testing.T) { removeFile = func(_, _ string) {} - s3fs := &S3fsMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return errors.New("failed to unmount") - }, - })} + s3fs := &S3fsMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return errors.New("failed to unmount") + }, + }), + } err := s3fs.Unmount(context.Background(), target) assert.Error(t, err) From 5b2ae21f7b6d62a970f7559a56f3931256445d5d Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 20:02:14 +0530 Subject: [PATCH 29/64] build fix --- pkg/mounter/mounter-rclone_test.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/pkg/mounter/mounter-rclone_test.go b/pkg/mounter/mounter-rclone_test.go index 6f290839..94e110bb 100644 --- a/pkg/mounter/mounter-rclone_test.go +++ b/pkg/mounter/mounter-rclone_test.go @@ -267,11 +267,14 @@ func TestRcloneUnmount_WorkerNode(t *testing.T) { func TestRcloneUnmount_WorkerNode_Negative(t *testing.T) { mountWorker = true - rclone := &RcloneMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return nil - }, - })} + rclone := &RcloneMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return nil + }, + }), + } mounterRequest = func(_ context.Context, _, _ string, _ *zap.Logger) error { return errors.New("failed to create http request") @@ -287,11 +290,14 @@ func TestRcloneUnmount_NodeServer_Negative(t *testing.T) { removeConfigFile = func(_, _ string) {} - rclone := &RcloneMounter{MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { - return errors.New("failed to unmount") - }, - })} + rclone := &RcloneMounter{ + logger: zap.NewNop(), + MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ + FuseUnmountFn: func(path string) error { + return errors.New("failed to unmount") + }, + }), + } err := rclone.Unmount(context.Background(), target) assert.Error(t, err) From 4d0a81673652ae38ac047a720ed0aac1734d485a Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 10 Jun 2026 21:18:27 +0530 Subject: [PATCH 30/64] build fix --- pkg/mounter/mounter_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/mounter/mounter_test.go b/pkg/mounter/mounter_test.go index 40350fe2..e7d2e7b7 100644 --- a/pkg/mounter/mounter_test.go +++ b/pkg/mounter/mounter_test.go @@ -133,6 +133,9 @@ func TestNewMounter(t *testing.T) { } s3fs.MountOptions = nil expected.MountOptions = nil + // Exclude logger from comparison as it's initialized internally + s3fs.logger = nil + expected.logger = nil } if rclone, ok := result.(*RcloneMounter); ok { expected := test.expected.(*RcloneMounter) @@ -141,6 +144,9 @@ func TestNewMounter(t *testing.T) { } rclone.MountOptions = nil expected.MountOptions = nil + // Exclude logger from comparison as it's initialized internally + rclone.logger = nil + expected.logger = nil } assert.Equal(t, result, test.expected) From 139268c286f668d911ddd4180b7d1b39c70f987c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 00:37:26 +0530 Subject: [PATCH 31/64] addning e2e test cases --- pkg/driver/controllerserver_test.go | 4 +- pkg/driver/identityserver_test.go | 7 + pkg/driver/interceptor_test.go | 279 +++++++++++++++++++++++ pkg/driver/requestid_integration_test.go | 279 +++++++++++++++++++++++ 4 files changed, 568 insertions(+), 1 deletion(-) create mode 100644 pkg/driver/interceptor_test.go create mode 100644 pkg/driver/requestid_integration_test.go diff --git a/pkg/driver/controllerserver_test.go b/pkg/driver/controllerserver_test.go index 3eb33e4b..4c5f3c71 100644 --- a/pkg/driver/controllerserver_test.go +++ b/pkg/driver/controllerserver_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/IBM/ibm-object-csi-driver/pkg/s3client" "github.com/IBM/ibm-object-csi-driver/pkg/utils" "github.com/container-storage-interface/spec/lib/go/csi" @@ -37,7 +38,8 @@ import ( ) var ( - ctx = context.Background() + // Create context with request ID for testing + ctx = requestid.WithRequestID(context.Background(), "test-request-id") driverName = "testDriver" driverVersion = "testDriverVersion" diff --git a/pkg/driver/identityserver_test.go b/pkg/driver/identityserver_test.go index 2869f34c..82406666 100644 --- a/pkg/driver/identityserver_test.go +++ b/pkg/driver/identityserver_test.go @@ -17,15 +17,22 @@ package driver import ( + "context" "errors" "reflect" "testing" + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/container-storage-interface/spec/lib/go/csi" "github.com/stretchr/testify/assert" "go.uber.org/zap" ) +var ( + // Create context with request ID for testing (shared with other test files in driver package) + testCtx = requestid.WithRequestID(context.Background(), "test-identity-request-id") +) + func TestGetPluginInfo(t *testing.T) { testCases := []struct { testCaseName string diff --git a/pkg/driver/interceptor_test.go b/pkg/driver/interceptor_test.go new file mode 100644 index 00000000..fcdda58a --- /dev/null +++ b/pkg/driver/interceptor_test.go @@ -0,0 +1,279 @@ +/** + * Copyright 2024 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package driver + +import ( + "context" + "errors" + "testing" + + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" + "google.golang.org/grpc" +) + +func TestUnaryServerInterceptor(t *testing.T) { + testCases := []struct { + name string + ctx context.Context + handler grpc.UnaryHandler + expectRequestID bool + expectError bool + expectedErrMsg string + }{ + { + name: "Generates new request ID when context is empty", + ctx: context.Background(), + handler: func(ctx context.Context, req interface{}) (interface{}, error) { + // Verify request ID exists in context + reqID := requestid.FromContext(ctx) + assert.NotEmpty(t, reqID, "Request ID should be present in context") + + // Verify it's a valid UUID + _, err := uuid.Parse(reqID) + assert.NoError(t, err, "Request ID should be a valid UUID") + + return "success", nil + }, + expectRequestID: true, + expectError: false, + }, + { + name: "Preserves existing request ID in context", + ctx: requestid.WithRequestID(context.Background(), "existing-request-id-123"), + handler: func(ctx context.Context, req interface{}) (interface{}, error) { + // Verify the existing request ID is preserved + reqID := requestid.FromContext(ctx) + assert.Equal(t, "existing-request-id-123", reqID, "Existing request ID should be preserved") + return "success", nil + }, + expectRequestID: true, + expectError: false, + }, + { + name: "Logs request ID on successful completion", + ctx: context.Background(), + handler: func(ctx context.Context, req interface{}) (interface{}, error) { + return "success", nil + }, + expectRequestID: true, + expectError: false, + }, + { + name: "Logs request ID on error", + ctx: context.Background(), + handler: func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, errors.New("test error") + }, + expectRequestID: true, + expectError: true, + expectedErrMsg: "test error", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create an observed logger to capture log entries + core, recorded := observer.New(zapcore.InfoLevel) + logger := zap.New(core) + + // Create the interceptor + interceptor := UnaryServerInterceptor(logger) + + // Create mock server info + info := &grpc.UnaryServerInfo{ + FullMethod: "/test.Service/TestMethod", + } + + // Call the interceptor + resp, err := interceptor(tc.ctx, nil, info, tc.handler) + + // Verify error handling + if tc.expectError { + assert.Error(t, err) + if tc.expectedErrMsg != "" { + assert.Contains(t, err.Error(), tc.expectedErrMsg) + } + } else { + assert.NoError(t, err) + assert.NotNil(t, resp) + } + + // Verify logs contain request ID + if tc.expectRequestID { + logs := recorded.All() + assert.NotEmpty(t, logs, "Should have log entries") + + // Check that logs contain request_id field + foundRequestID := false + var capturedRequestID string + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" { + foundRequestID = true + capturedRequestID = field.String + + // Verify it's not empty + assert.NotEmpty(t, capturedRequestID, "Request ID in logs should not be empty") + + // If we had an existing request ID, verify it matches + if existingID := requestid.FromContext(tc.ctx); existingID != "" { + assert.Equal(t, existingID, capturedRequestID, "Logged request ID should match context") + } + break + } + } + } + assert.True(t, foundRequestID, "Logs should contain request_id field") + + // Verify all logs for this request have the same request ID + requestIDs := make(map[string]bool) + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" { + requestIDs[field.String] = true + } + } + } + assert.Equal(t, 1, len(requestIDs), "All logs should have the same request ID") + } + + // Verify log messages + logs := recorded.All() + if tc.expectError { + // Should have "started" and "failed" logs + var hasStarted, hasFailed bool + for _, log := range logs { + if log.Message == "gRPC request started" { + hasStarted = true + } + if log.Message == "gRPC request failed" { + hasFailed = true + } + } + assert.True(t, hasStarted, "Should log request started") + assert.True(t, hasFailed, "Should log request failed") + } else { + // Should have "started" and "completed" logs + var hasStarted, hasCompleted bool + for _, log := range logs { + if log.Message == "gRPC request started" { + hasStarted = true + } + if log.Message == "gRPC request completed" { + hasCompleted = true + } + } + assert.True(t, hasStarted, "Should log request started") + assert.True(t, hasCompleted, "Should log request completed") + } + }) + } +} + +func TestUnaryServerInterceptor_RequestIDPropagation(t *testing.T) { + // Create an observed logger + core, recorded := observer.New(zapcore.InfoLevel) + logger := zap.New(core) + + // Create the interceptor + interceptor := UnaryServerInterceptor(logger) + + // Track the request ID through nested calls + var capturedRequestID string + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + capturedRequestID = requestid.FromContext(ctx) + + // Simulate nested operation that uses the same context + nestedFunc := func(ctx context.Context) string { + return requestid.FromContext(ctx) + } + + nestedRequestID := nestedFunc(ctx) + assert.Equal(t, capturedRequestID, nestedRequestID, "Request ID should propagate to nested calls") + + return "success", nil + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "/test.Service/TestMethod", + } + + // Call the interceptor + _, err := interceptor(context.Background(), nil, info, handler) + assert.NoError(t, err) + + // Verify request ID was captured + assert.NotEmpty(t, capturedRequestID, "Request ID should be captured from context") + + // Verify it's a valid UUID + _, parseErr := uuid.Parse(capturedRequestID) + assert.NoError(t, parseErr, "Request ID should be a valid UUID") + + // Verify logs contain the same request ID + logs := recorded.All() + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" { + assert.Equal(t, capturedRequestID, field.String, "All logs should have the same request ID") + } + } + } +} + +func TestUnaryServerInterceptor_DurationLogging(t *testing.T) { + // Create an observed logger + core, recorded := observer.New(zapcore.InfoLevel) + logger := zap.New(core) + + // Create the interceptor + interceptor := UnaryServerInterceptor(logger) + + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return "success", nil + } + + info := &grpc.UnaryServerInfo{ + FullMethod: "/test.Service/TestMethod", + } + + // Call the interceptor + _, err := interceptor(context.Background(), nil, info, handler) + assert.NoError(t, err) + + // Verify duration is logged + logs := recorded.All() + foundDuration := false + for _, log := range logs { + if log.Message == "gRPC request completed" { + for _, field := range log.Context { + if field.Key == "duration" { + foundDuration = true + assert.Greater(t, field.Integer, int64(0), "Duration should be greater than 0") + break + } + } + } + } + assert.True(t, foundDuration, "Should log request duration") +} + +// Made with Bob diff --git a/pkg/driver/requestid_integration_test.go b/pkg/driver/requestid_integration_test.go new file mode 100644 index 00000000..3939bc9c --- /dev/null +++ b/pkg/driver/requestid_integration_test.go @@ -0,0 +1,279 @@ +/** + * Copyright 2024 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package driver + +import ( + "context" + "testing" + + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "github.com/container-storage-interface/spec/lib/go/csi" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" + "google.golang.org/grpc" +) + +// TestRequestIDEndToEndFlow tests the complete request ID flow from +// interceptor through CSI handlers to verify proper propagation +func TestRequestIDEndToEndFlow(t *testing.T) { + // Create an observed logger to capture all log entries + core, recorded := observer.New(zapcore.InfoLevel) + logger := zap.New(core) + + // Create identity server + s3Driver := &S3Driver{ + name: "test-driver", + version: "1.0.0", + logger: logger, + } + identityServer := &identityServer{ + S3Driver: s3Driver, + } + + // Create the interceptor + interceptor := UnaryServerInterceptor(logger) + + // Test GetPluginInfo through the interceptor + t.Run("GetPluginInfo with request ID propagation", func(t *testing.T) { + recorded.TakeAll() // Clear previous logs + + req := &csi.GetPluginInfoRequest{} + ctx := context.Background() + + // Handler that will be called by interceptor + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + // Verify request ID exists in context + reqID := requestid.FromContext(ctx) + assert.NotEmpty(t, reqID, "Request ID should be present in context") + + // Call the actual CSI method + return identityServer.GetPluginInfo(ctx, req.(*csi.GetPluginInfoRequest)) + } + + // Call through interceptor + resp, err := interceptor(ctx, req, &grpc.UnaryServerInfo{ + FullMethod: "/csi.v1.Identity/GetPluginInfo", + }, handler) + + // Verify response + assert.NoError(t, err) + assert.NotNil(t, resp) + + pluginResp, ok := resp.(*csi.GetPluginInfoResponse) + assert.True(t, ok) + assert.Equal(t, "test-driver", pluginResp.Name) + + // Verify logs contain request ID + logs := recorded.All() + assert.NotEmpty(t, logs, "Should have log entries") + + // Extract request ID from logs + var requestIDs []string + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" { + requestIDs = append(requestIDs, field.String) + } + } + } + + // Verify all logs have the same request ID + assert.NotEmpty(t, requestIDs, "Should have request IDs in logs") + firstReqID := requestIDs[0] + assert.NotEmpty(t, firstReqID, "Request ID should not be empty") + + for _, reqID := range requestIDs { + assert.Equal(t, firstReqID, reqID, "All logs should have the same request ID") + } + + // Verify we have both start and completion logs + var hasStartLog, hasCompletionLog bool + for _, log := range logs { + if log.Message == "gRPC request started" { + hasStartLog = true + } + if log.Message == "gRPC request completed" { + hasCompletionLog = true + } + } + assert.True(t, hasStartLog, "Should have request started log") + assert.True(t, hasCompletionLog, "Should have request completed log") + }) + + t.Run("Probe with existing request ID", func(t *testing.T) { + recorded.TakeAll() // Clear previous logs + + req := &csi.ProbeRequest{} + existingReqID := "existing-probe-request-id" + ctx := requestid.WithRequestID(context.Background(), existingReqID) + + // Handler that will be called by interceptor + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + // Verify the existing request ID is preserved + reqID := requestid.FromContext(ctx) + assert.Equal(t, existingReqID, reqID, "Should preserve existing request ID") + + // Call the actual CSI method + return identityServer.Probe(ctx, req.(*csi.ProbeRequest)) + } + + // Call through interceptor + resp, err := interceptor(ctx, req, &grpc.UnaryServerInfo{ + FullMethod: "/csi.v1.Identity/Probe", + }, handler) + + // Verify response + assert.NoError(t, err) + assert.NotNil(t, resp) + + // Verify logs contain the existing request ID + logs := recorded.All() + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" { + assert.Equal(t, existingReqID, field.String, "Logs should contain existing request ID") + } + } + } + }) +} + +// TestRequestIDPropagationToLogger tests that request ID properly +// propagates to logger instances +func TestRequestIDPropagationToLogger(t *testing.T) { + // Create an observed logger at DEBUG level to capture all logs + core, recorded := observer.New(zapcore.DebugLevel) + logger := zap.New(core) + + testReqID := "test-logger-request-id" + ctx := requestid.WithRequestID(context.Background(), testReqID) + + // Create identity server + s3Driver := &S3Driver{ + name: "test-driver", + version: "1.0.0", + logger: logger, + } + identityServer := &identityServer{ + S3Driver: s3Driver, + } + + // Call GetPluginInfo which should log with request ID + req := &csi.GetPluginInfoRequest{} + resp, err := identityServer.GetPluginInfo(ctx, req) + + assert.NoError(t, err) + assert.NotNil(t, resp) + + // Verify logs contain the request ID + logs := recorded.All() + assert.NotEmpty(t, logs, "Should have log entries") + + foundRequestID := false + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" && field.String == testReqID { + foundRequestID = true + break + } + } + } + assert.True(t, foundRequestID, "Logs should contain the request ID") +} + +// TestRequestIDInMultipleHandlers tests request ID propagation +// across different CSI handler types +func TestRequestIDInMultipleHandlers(t *testing.T) { + // Create an observed logger + core, recorded := observer.New(zapcore.InfoLevel) + logger := zap.New(core) + + testReqID := "multi-handler-request-id" + ctx := requestid.WithRequestID(context.Background(), testReqID) + + // Create servers + s3Driver := &S3Driver{ + name: "test-driver", + version: "1.0.0", + logger: logger, + } + + identityServer := &identityServer{S3Driver: s3Driver} + nodeServer := &nodeServer{S3Driver: s3Driver} + + testCases := []struct { + name string + handler func() error + }{ + { + name: "IdentityServer.GetPluginInfo", + handler: func() error { + _, err := identityServer.GetPluginInfo(ctx, &csi.GetPluginInfoRequest{}) + return err + }, + }, + { + name: "IdentityServer.GetPluginCapabilities", + handler: func() error { + _, err := identityServer.GetPluginCapabilities(ctx, &csi.GetPluginCapabilitiesRequest{}) + return err + }, + }, + { + name: "IdentityServer.Probe", + handler: func() error { + _, err := identityServer.Probe(ctx, &csi.ProbeRequest{}) + return err + }, + }, + { + name: "NodeServer.NodeGetCapabilities", + handler: func() error { + _, err := nodeServer.NodeGetCapabilities(ctx, &csi.NodeGetCapabilitiesRequest{}) + return err + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + recorded.TakeAll() // Clear previous logs + + err := tc.handler() + assert.NoError(t, err) + + // Verify logs contain the request ID + logs := recorded.All() + if len(logs) > 0 { + foundRequestID := false + for _, log := range logs { + for _, field := range log.Context { + if field.Key == "request_id" && field.String == testReqID { + foundRequestID = true + break + } + } + } + assert.True(t, foundRequestID, "Logs should contain the request ID for "+tc.name) + } + }) + } +} + +// Made with Bob From 5a24adb175197f8ef1351dad049cb5174889dd48 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 00:43:09 +0530 Subject: [PATCH 32/64] build fix --- pkg/driver/identityserver_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/driver/identityserver_test.go b/pkg/driver/identityserver_test.go index 82406666..2869f34c 100644 --- a/pkg/driver/identityserver_test.go +++ b/pkg/driver/identityserver_test.go @@ -17,22 +17,15 @@ package driver import ( - "context" "errors" "reflect" "testing" - "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/container-storage-interface/spec/lib/go/csi" "github.com/stretchr/testify/assert" "go.uber.org/zap" ) -var ( - // Create context with request ID for testing (shared with other test files in driver package) - testCtx = requestid.WithRequestID(context.Background(), "test-identity-request-id") -) - func TestGetPluginInfo(t *testing.T) { testCases := []struct { testCaseName string From acc2d2a1823e7cf101ca05e9671d5399ab4422b2 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 10:45:52 +0530 Subject: [PATCH 33/64] test case fixing for build --- pkg/driver/controllerserver_test.go | 8 ++++---- pkg/driver/nodeserver_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/driver/controllerserver_test.go b/pkg/driver/controllerserver_test.go index 4c5f3c71..7702569a 100644 --- a/pkg/driver/controllerserver_test.go +++ b/pkg/driver/controllerserver_test.go @@ -407,7 +407,7 @@ func TestCreateVolume(t *testing.T) { }, }), expectedResp: nil, - expectedErr: errors.New("[] secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations"), + expectedErr: errors.New("[test-request-id] secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations"), }, { testCaseName: "Negative: Secret and PVC Names Different, Failed to get Secret", @@ -566,7 +566,7 @@ func TestCreateVolume(t *testing.T) { driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, expectedErr: status.Error(codes.InvalidArgument, - "[] resourceConfigApiKey missing in secret, cannot set quota limit for bucket"), + "[test-request-id] resourceConfigApiKey missing in secret, cannot set quota limit for bucket"), }, { @@ -589,7 +589,7 @@ func TestCreateVolume(t *testing.T) { cosSession: &s3client.FakeCOSSessionFactory{}, driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, - expectedErr: status.Error(codes.InvalidArgument, `[] invalid quotaLimit value "yes": must be 'true' or 'false'`), + expectedErr: status.Error(codes.InvalidArgument, `[test-request-id] invalid quotaLimit value "yes": must be 'true' or 'false'`), }, { testCaseName: "Negative: quotaLimit=true with zero capacity (direct secrets)", @@ -612,7 +612,7 @@ func TestCreateVolume(t *testing.T) { cosSession: &s3client.FakeCOSSessionFactory{}, driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, - expectedErr: status.Error(codes.InvalidArgument, "[] enable quotaLimit requested but no positive storage size requested in PVC"), + expectedErr: status.Error(codes.InvalidArgument, "[test-request-id] enable quotaLimit requested but no positive storage size requested in PVC"), }, { testCaseName: "Positive: quotaLimit=true with positive capacity (direct secrets)", diff --git a/pkg/driver/nodeserver_test.go b/pkg/driver/nodeserver_test.go index 41a5c332..ae876151 100644 --- a/pkg/driver/nodeserver_test.go +++ b/pkg/driver/nodeserver_test.go @@ -545,7 +545,7 @@ func TestNodeGetVolumeStats(t *testing.T) { expectedResp: &csi.NodeGetVolumeStatsResponse{ VolumeCondition: &csi.VolumeCondition{ Abnormal: true, - Message: "[] transpoint endpoint is not connected", + Message: "[test-request-id] transpoint endpoint is not connected", }, }, expectedErr: nil, From c16b3009ad7ff82c3b5f35c8386f9076ce4e94e3 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 11:06:18 +0530 Subject: [PATCH 34/64] increaseing code coverage --- pkg/logger/logger_test.go | 384 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 pkg/logger/logger_test.go diff --git a/pkg/logger/logger_test.go b/pkg/logger/logger_test.go new file mode 100644 index 00000000..61882943 --- /dev/null +++ b/pkg/logger/logger_test.go @@ -0,0 +1,384 @@ +/******************************************************************************* + * IBM Confidential + * OCO Source Materials + * IBM Cloud Kubernetes Service, 5737-D43 + * (C) Copyright IBM Corp. 2023 All Rights Reserved. + * The source code for this program is not published or otherwise divested of + * its trade secrets, irrespective of what has been deposited with + * the U.S. Copyright Office. + ******************************************************************************/ + +package logger + +import ( + "context" + "testing" + + "github.com/IBM/ibm-object-csi-driver/pkg/requestid" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" +) + +func TestWithRequestID(t *testing.T) { + tests := []struct { + name string + ctx context.Context + logger *zap.Logger + expectedReqID string + expectReqIDSet bool + }{ + { + name: "Context with request ID", + ctx: requestid.WithRequestID(context.Background(), "test-req-123"), + logger: zap.NewNop(), + expectedReqID: "test-req-123", + expectReqIDSet: true, + }, + { + name: "Context without request ID", + ctx: context.Background(), + logger: zap.NewNop(), + expectedReqID: "", + expectReqIDSet: false, + }, + { + name: "Nil logger", + ctx: requestid.WithRequestID(context.Background(), "test-req-456"), + logger: nil, + expectedReqID: "", + expectReqIDSet: false, + }, + { + name: "Empty request ID", + ctx: requestid.WithRequestID(context.Background(), ""), + logger: zap.NewNop(), + expectedReqID: "", + expectReqIDSet: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := WithRequestID(tt.ctx, tt.logger) + + if tt.logger == nil { + assert.Nil(t, result, "Expected nil logger when input is nil") + return + } + + assert.NotNil(t, result, "Expected non-nil logger") + + // Verify request ID is added by logging and checking fields + if tt.expectReqIDSet { + core, recorded := observer.New(zapcore.InfoLevel) + testLogger := zap.New(core) + resultLogger := WithRequestID(tt.ctx, testLogger) + resultLogger.Info("test message") + + entries := recorded.All() + assert.Len(t, entries, 1, "Expected one log entry") + if len(entries) > 0 { + fields := entries[0].Context + found := false + for _, field := range fields { + if field.Key == "request_id" && field.String == tt.expectedReqID { + found = true + break + } + } + assert.True(t, found, "Expected request_id field with value %s", tt.expectedReqID) + } + } + }) + } +} + +func TestInfo(t *testing.T) { + core, recorded := observer.New(zapcore.InfoLevel) + logger := zap.New(core) + + tests := []struct { + name string + ctx context.Context + msg string + fields []zap.Field + expectedReqID string + }{ + { + name: "Info with request ID", + ctx: requestid.WithRequestID(context.Background(), "info-req-123"), + msg: "test info message", + fields: []zap.Field{zap.String("key", "value")}, + expectedReqID: "info-req-123", + }, + { + name: "Info without request ID", + ctx: context.Background(), + msg: "test info without req id", + fields: []zap.Field{}, + expectedReqID: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + recorded.TakeAll() // Clear previous entries + + Info(tt.ctx, logger, tt.msg, tt.fields...) + + entries := recorded.All() + assert.Len(t, entries, 1, "Expected one log entry") + assert.Equal(t, tt.msg, entries[0].Message) + assert.Equal(t, zapcore.InfoLevel, entries[0].Level) + + if tt.expectedReqID != "" { + found := false + for _, field := range entries[0].Context { + if field.Key == "request_id" && field.String == tt.expectedReqID { + found = true + break + } + } + assert.True(t, found, "Expected request_id field") + } + }) + } +} + +func TestError(t *testing.T) { + core, recorded := observer.New(zapcore.ErrorLevel) + logger := zap.New(core) + + tests := []struct { + name string + ctx context.Context + msg string + fields []zap.Field + expectedReqID string + }{ + { + name: "Error with request ID", + ctx: requestid.WithRequestID(context.Background(), "error-req-456"), + msg: "test error message", + fields: []zap.Field{zap.Error(assert.AnError)}, + expectedReqID: "error-req-456", + }, + { + name: "Error without request ID", + ctx: context.Background(), + msg: "test error without req id", + fields: []zap.Field{}, + expectedReqID: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + recorded.TakeAll() // Clear previous entries + + Error(tt.ctx, logger, tt.msg, tt.fields...) + + entries := recorded.All() + assert.Len(t, entries, 1, "Expected one log entry") + assert.Equal(t, tt.msg, entries[0].Message) + assert.Equal(t, zapcore.ErrorLevel, entries[0].Level) + + if tt.expectedReqID != "" { + found := false + for _, field := range entries[0].Context { + if field.Key == "request_id" && field.String == tt.expectedReqID { + found = true + break + } + } + assert.True(t, found, "Expected request_id field") + } + }) + } +} + +func TestWarn(t *testing.T) { + core, recorded := observer.New(zapcore.WarnLevel) + logger := zap.New(core) + + tests := []struct { + name string + ctx context.Context + msg string + fields []zap.Field + expectedReqID string + }{ + { + name: "Warn with request ID", + ctx: requestid.WithRequestID(context.Background(), "warn-req-789"), + msg: "test warning message", + fields: []zap.Field{zap.String("warning", "details")}, + expectedReqID: "warn-req-789", + }, + { + name: "Warn without request ID", + ctx: context.Background(), + msg: "test warning without req id", + fields: []zap.Field{}, + expectedReqID: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + recorded.TakeAll() // Clear previous entries + + Warn(tt.ctx, logger, tt.msg, tt.fields...) + + entries := recorded.All() + assert.Len(t, entries, 1, "Expected one log entry") + assert.Equal(t, tt.msg, entries[0].Message) + assert.Equal(t, zapcore.WarnLevel, entries[0].Level) + + if tt.expectedReqID != "" { + found := false + for _, field := range entries[0].Context { + if field.Key == "request_id" && field.String == tt.expectedReqID { + found = true + break + } + } + assert.True(t, found, "Expected request_id field") + } + }) + } +} + +func TestDebug(t *testing.T) { + core, recorded := observer.New(zapcore.DebugLevel) + logger := zap.New(core) + + tests := []struct { + name string + ctx context.Context + msg string + fields []zap.Field + expectedReqID string + }{ + { + name: "Debug with request ID", + ctx: requestid.WithRequestID(context.Background(), "debug-req-abc"), + msg: "test debug message", + fields: []zap.Field{zap.String("debug", "info")}, + expectedReqID: "debug-req-abc", + }, + { + name: "Debug without request ID", + ctx: context.Background(), + msg: "test debug without req id", + fields: []zap.Field{}, + expectedReqID: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + recorded.TakeAll() // Clear previous entries + + Debug(tt.ctx, logger, tt.msg, tt.fields...) + + entries := recorded.All() + assert.Len(t, entries, 1, "Expected one log entry") + assert.Equal(t, tt.msg, entries[0].Message) + assert.Equal(t, zapcore.DebugLevel, entries[0].Level) + + if tt.expectedReqID != "" { + found := false + for _, field := range entries[0].Context { + if field.Key == "request_id" && field.String == tt.expectedReqID { + found = true + break + } + } + assert.True(t, found, "Expected request_id field") + } + }) + } +} + +func TestFatal(t *testing.T) { + // Fatal calls os.Exit, so we can't test it directly + // Instead, we verify that WithRequestID works correctly and would pass the right logger + core, _ := observer.New(zapcore.FatalLevel) + logger := zap.New(core) + + ctx := requestid.WithRequestID(context.Background(), "fatal-req-xyz") + + // Test that WithRequestID returns a logger with request ID + loggerWithReqID := WithRequestID(ctx, logger) + assert.NotNil(t, loggerWithReqID) + + // We can't actually call Fatal as it would exit the test + // The function is covered by the WithRequestID test and integration tests +} + +func TestPanic(t *testing.T) { + core, recorded := observer.New(zapcore.PanicLevel) + logger := zap.New(core) + + ctx := requestid.WithRequestID(context.Background(), "panic-req-def") + msg := "test panic message" + + // Panic will actually panic, so we need to recover + defer func() { + if r := recover(); r != nil { + // Expected panic + entries := recorded.All() + assert.Len(t, entries, 1, "Expected one log entry") + assert.Equal(t, msg, entries[0].Message) + assert.Equal(t, zapcore.PanicLevel, entries[0].Level) + + found := false + for _, field := range entries[0].Context { + if field.Key == "request_id" && field.String == "panic-req-def" { + found = true + break + } + } + assert.True(t, found, "Expected request_id field") + } + }() + + Panic(ctx, logger, msg) + t.Fatal("Expected panic but didn't occur") +} + +func TestAllLogLevelsWithRequestID(t *testing.T) { + // Test that all log levels properly include request ID + core, recorded := observer.New(zapcore.DebugLevel) + logger := zap.New(core) + ctx := requestid.WithRequestID(context.Background(), "multi-level-req") + + // Test Info + Info(ctx, logger, "info message") + // Test Error + Error(ctx, logger, "error message") + // Test Warn + Warn(ctx, logger, "warn message") + // Test Debug + Debug(ctx, logger, "debug message") + + entries := recorded.All() + assert.Len(t, entries, 4, "Expected four log entries") + + // Verify all entries have request ID + for _, entry := range entries { + found := false + for _, field := range entry.Context { + if field.Key == "request_id" && field.String == "multi-level-req" { + found = true + break + } + } + assert.True(t, found, "Expected request_id in %s level log", entry.Level) + } +} + +// Made with Bob From def1c6ef5e9d9e38ff3a7393815efe4e1e615272 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 20:46:05 +0530 Subject: [PATCH 35/64] minor fix --- pkg/driver/interceptor_test.go | 2 -- pkg/driver/requestid_integration_test.go | 2 -- pkg/logger/logger_test.go | 2 -- pkg/mounter/utils/mounter_utils.go | 2 -- 4 files changed, 8 deletions(-) diff --git a/pkg/driver/interceptor_test.go b/pkg/driver/interceptor_test.go index fcdda58a..695ac79c 100644 --- a/pkg/driver/interceptor_test.go +++ b/pkg/driver/interceptor_test.go @@ -275,5 +275,3 @@ func TestUnaryServerInterceptor_DurationLogging(t *testing.T) { } assert.True(t, foundDuration, "Should log request duration") } - -// Made with Bob diff --git a/pkg/driver/requestid_integration_test.go b/pkg/driver/requestid_integration_test.go index 3939bc9c..c2565374 100644 --- a/pkg/driver/requestid_integration_test.go +++ b/pkg/driver/requestid_integration_test.go @@ -275,5 +275,3 @@ func TestRequestIDInMultipleHandlers(t *testing.T) { }) } } - -// Made with Bob diff --git a/pkg/logger/logger_test.go b/pkg/logger/logger_test.go index 61882943..feec296b 100644 --- a/pkg/logger/logger_test.go +++ b/pkg/logger/logger_test.go @@ -380,5 +380,3 @@ func TestAllLogLevelsWithRequestID(t *testing.T) { assert.True(t, found, "Expected request_id in %s level log", entry.Level) } } - -// Made with Bob diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index 25b83ef3..61eadd92 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -315,5 +315,3 @@ func waitForProcess(p *os.Process, backoff int) error { time.Sleep(time.Duration(500) * time.Millisecond) return waitForProcess(p, backoff+1) } - -// Made with Bob From 9353788a555c53f887ec61ed7cdde98eac154c7a Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 21:10:25 +0530 Subject: [PATCH 36/64] minor log changes --- pkg/driver/controllerserver.go | 53 +++++++++++++++++----------------- pkg/driver/nodeserver.go | 43 +++++++++++++++------------ 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index 64e3317b..f77ce035 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -46,7 +46,7 @@ type controllerServer struct { func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { // Extract request ID from context (added by interceptor) reqID := requestid.FromContext(ctx) - + var ( bucketName string endPoint string @@ -377,7 +377,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol params["userProvidedBucket"] = "false" params["bucketName"] = tempBucketName } - + logger.Info(ctx, cs.Logger, "CreateVolume completed successfully", zap.String("volume_id", volumeID), zap.String("bucket_name", params["bucketName"]), @@ -395,9 +395,15 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { // Extract request ID from context reqID := requestid.FromContext(ctx) - - logger.Info(ctx, cs.Logger, "DeleteVolume started") - + + volumeID := req.GetVolumeId() + if len(volumeID) == 0 { + logger.Error(ctx, cs.Logger, "Volume ID missing in request") + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + } + + logger.Info(ctx, cs.Logger, "DeleteVolume started", zap.String("volume_id", volumeID)) + modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { logger.Error(ctx, cs.Logger, "Error modifying request", zap.Error(err)) @@ -405,13 +411,6 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol } logger.Debug(ctx, cs.Logger, "DeleteVolume request details", zap.Any("request", modifiedRequest.(*csi.DeleteVolumeRequest))) - volumeID := req.GetVolumeId() - if len(volumeID) == 0 { - logger.Error(ctx, cs.Logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) - } - logger.Info(ctx, cs.Logger, "Deleting volume", zap.String("volume_id", volumeID)) - secretMap := req.GetSecrets() logger.Info(ctx, cs.Logger, "Secrets received", zap.Int("secret_count", len(secretMap))) @@ -490,13 +489,15 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol logger.Info(ctx, cs.Logger, "No bucket to delete") } - logger.Info(ctx, cs.Logger, "DeleteVolume completed successfully", zap.String("volume_id", volumeID)) + logger.Info(ctx, cs.Logger, "DeleteVolume completed successfully", + zap.String("volume_id", volumeID), + zap.String("bucket_name", bucketToDelete)) return &csi.DeleteVolumeResponse{}, nil } func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ControllerPublishVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerPublishVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerPublishVolume", reqID)) @@ -504,7 +505,7 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ControllerUnpublishVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerUnpublishVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerUnpublishVolume", reqID)) @@ -512,7 +513,7 @@ func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req * func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Info(ctx, cs.Logger, "ValidateVolumeCapabilities started") logger.Debug(ctx, cs.Logger, "ValidateVolumeCapabilities request", zap.Any("request", req)) @@ -545,7 +546,7 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ListVolumes request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ListVolumes not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListVolumes", reqID)) @@ -553,7 +554,7 @@ func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolume func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "GetCapacity request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "GetCapacity not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] GetCapacity", reqID)) @@ -562,7 +563,7 @@ func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacit func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { logger.Info(ctx, cs.Logger, "ControllerGetCapabilities started") logger.Debug(ctx, cs.Logger, "ControllerGetCapabilities request", zap.Any("request", req)) - + var caps []*csi.ControllerServiceCapability for _, cap := range controllerCapabilities { c := &csi.ControllerServiceCapability{ @@ -574,14 +575,14 @@ func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req * } caps = append(caps, c) } - + logger.Info(ctx, cs.Logger, "ControllerGetCapabilities completed", zap.Int("capability_count", len(caps))) return &csi.ControllerGetCapabilitiesResponse{Capabilities: caps}, nil } func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "CreateSnapshot request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "CreateSnapshot not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] CreateSnapshot", reqID)) @@ -589,7 +590,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "DeleteSnapshot request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "DeleteSnapshot not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] DeleteSnapshot", reqID)) @@ -597,7 +598,7 @@ func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ListSnapshots request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ListSnapshots not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListSnapshots", reqID)) @@ -605,7 +606,7 @@ func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnap func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ControllerExpandVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerExpandVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerExpandVolume", reqID)) @@ -613,7 +614,7 @@ func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi func (cs *controllerServer) ControllerGetVolume(ctx context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ControllerGetVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerGetVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerGetVolume", reqID)) @@ -621,7 +622,7 @@ func (cs *controllerServer) ControllerGetVolume(ctx context.Context, req *csi.Co func (cs *controllerServer) ControllerModifyVolume(ctx context.Context, req *csi.ControllerModifyVolumeRequest) (*csi.ControllerModifyVolumeResponse, error) { reqID := requestid.FromContext(ctx) - + logger.Debug(ctx, cs.Logger, "ControllerModifyVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerModifyVolume not implemented") return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerModifyVolume", reqID)) diff --git a/pkg/driver/nodeserver.go b/pkg/driver/nodeserver.go index 16a7fb76..5883108c 100644 --- a/pkg/driver/nodeserver.go +++ b/pkg/driver/nodeserver.go @@ -95,18 +95,6 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - logger.Info(ctx, ns.logger, "NodePublishVolume started") - - modifiedRequest, err := utils.ReplaceAndReturnCopy(req) - if err != nil { - logger.Error(ctx, ns.logger, "Error modifying request", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) - } - logger.Debug(ctx, ns.logger, "NodePublishVolume request", zap.Any("request", modifiedRequest.(*csi.NodePublishVolumeRequest))) - - volumeMountGroup := req.GetVolumeCapability().GetMount().GetVolumeMountGroup() - logger.Debug(ctx, ns.logger, "Volume mount group", zap.String("volume_mount_group", volumeMountGroup)) - volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") @@ -119,6 +107,20 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } + logger.Info(ctx, ns.logger, "NodePublishVolume started", + zap.String("volume_id", volumeID), + zap.String("target_path", targetPath)) + + modifiedRequest, err := utils.ReplaceAndReturnCopy(req) + if err != nil { + logger.Error(ctx, ns.logger, "Error modifying request", zap.Error(err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) + } + logger.Debug(ctx, ns.logger, "NodePublishVolume request", zap.Any("request", modifiedRequest.(*csi.NodePublishVolumeRequest))) + + volumeMountGroup := req.GetVolumeCapability().GetMount().GetVolumeMountGroup() + logger.Debug(ctx, ns.logger, "Volume mount group", zap.String("volume_mount_group", volumeMountGroup)) + if req.GetVolumeCapability() == nil { logger.Error(ctx, ns.logger, "Volume capability missing in request") return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capability missing in request", reqID)) @@ -220,17 +222,15 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } logger.Info(ctx, ns.logger, "NodePublishVolume completed successfully", - zap.String("bucket_name", secretMap["bucketName"]), - zap.String("target_path", targetPath)) + zap.String("volume_id", volumeID), + zap.String("target_path", targetPath), + zap.String("bucket_name", secretMap["bucketName"])) return &csi.NodePublishVolumeResponse{}, nil } func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { reqID := requestid.FromContext(ctx) - logger.Info(ctx, ns.logger, "NodeUnpublishVolume started") - logger.Debug(ctx, ns.logger, "NodeUnpublishVolume request", zap.Any("request", req)) - volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") @@ -243,6 +243,11 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) } + logger.Info(ctx, ns.logger, "NodeUnpublishVolume started", + zap.String("volume_id", volumeID), + zap.String("target_path", targetPath)) + logger.Debug(ctx, ns.logger, "NodeUnpublishVolume request", zap.Any("request", req)) + logger.Info(ctx, ns.logger, "Unmounting target path", zap.String("target_path", targetPath)) attrib, err := ns.Stats.GetPVAttributes(volumeID) @@ -260,7 +265,9 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) } - logger.Info(ctx, ns.logger, "NodeUnpublishVolume completed successfully", zap.String("target_path", targetPath)) + logger.Info(ctx, ns.logger, "NodeUnpublishVolume completed successfully", + zap.String("volume_id", volumeID), + zap.String("target_path", targetPath)) return &csi.NodeUnpublishVolumeResponse{}, nil } From e8f7e90a5ec4eae909ffaa1df144e76b4d125fd6 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 22:28:44 +0530 Subject: [PATCH 37/64] consistance logging --- pkg/driver/controllerserver.go | 100 ++++++++++++---------------- pkg/driver/controllerserver_test.go | 8 +-- pkg/driver/nodeserver.go | 47 ++++++------- pkg/driver/nodeserver_test.go | 2 +- 4 files changed, 68 insertions(+), 89 deletions(-) diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go index f77ce035..5f928124 100644 --- a/pkg/driver/controllerserver.go +++ b/pkg/driver/controllerserver.go @@ -23,7 +23,6 @@ import ( "github.com/IBM/ibm-object-csi-driver/pkg/constants" "github.com/IBM/ibm-object-csi-driver/pkg/logger" - "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/IBM/ibm-object-csi-driver/pkg/s3client" "github.com/IBM/ibm-object-csi-driver/pkg/utils" "github.com/aws/smithy-go" @@ -45,7 +44,6 @@ type controllerServer struct { func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { // Extract request ID from context (added by interceptor) - reqID := requestid.FromContext(ctx) var ( bucketName string @@ -63,32 +61,32 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { logger.Error(ctx, cs.Logger, "Error modifying request", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in modifying requests: %v", err)) } logger.Debug(ctx, cs.Logger, "CreateVolume request details", zap.Any("request", modifiedRequest.(*csi.CreateVolumeRequest))) volumeName, err := sanitizeVolumeID(req.GetName()) if err != nil { logger.Error(ctx, cs.Logger, "Error sanitizing volume ID", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in sanitizeVolumeID %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in sanitizeVolumeID: %v", err)) } volumeID := volumeName if len(volumeID) == 0 { logger.Error(ctx, cs.Logger, "Volume name missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume name missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume name missing in request") } logger.Info(ctx, cs.Logger, "Processing volume creation", zap.String("volume_id", volumeID)) caps := req.GetVolumeCapabilities() if caps == nil { logger.Error(ctx, cs.Logger, "Volume capabilities missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume Capabilities missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume Capabilities missing in request") } for _, cap := range caps { logger.Debug(ctx, cs.Logger, "Volume capability", zap.String("capability", cap.String())) if cap.GetBlock() != nil { logger.Error(ctx, cs.Logger, "Block volume not supported") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume type block Volume not supported", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume type block Volume not supported") } } @@ -110,7 +108,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if pvcName == "" { logger.Error(ctx, cs.Logger, "PVC name not specified") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] pvcName not specified, could not fetch the secret", reqID)) + return nil, status.Error(codes.InvalidArgument, "pvcName not specified, could not fetch the secret") } if pvcNamespace == "" { @@ -121,7 +119,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol pvcRes, err := cs.Stats.GetPVC(pvcName, pvcNamespace) if err != nil { logger.Error(ctx, cs.Logger, "PVC resource not found", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] PVC resource not found %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("PVC resource not found: %v", err)) } logger.Debug(ctx, cs.Logger, "PVC annotations", zap.Any("annotations", pvcRes.Annotations)) @@ -133,7 +131,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if customSecretName == "" { logger.Error(ctx, cs.Logger, "Secret name annotation not found in PVC") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations", reqID)) + return nil, status.Error(codes.InvalidArgument, "secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations") } if secretNamespace == "" { @@ -145,7 +143,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol secret, err := cs.Stats.GetSecret(customSecretName, secretNamespace) if err != nil { logger.Error(ctx, cs.Logger, "Secret resource not found", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Secret resource not found: %v", err)) } secretMapCustom := parseCustomSecret(ctx, secret, cs.Logger) @@ -166,21 +164,21 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if err != nil { logger.Error(ctx, cs.Logger, "Invalid quota limit value", zap.String("value", quotaLimitStr), zap.Error(err)) return nil, status.Error(codes.InvalidArgument, - fmt.Sprintf("[%s] invalid quotaLimit value %q: must be 'true' or 'false'", reqID, quotaLimitStr)) + fmt.Sprintf("invalid quotaLimit value %q: must be 'true' or 'false'", quotaLimitStr)) } if quotaLimitEnabled { if secretMap[constants.ResourceConfigApiKey] == "" { logger.Error(ctx, cs.Logger, "Resource config API key missing for quota limit") return nil, status.Error(codes.InvalidArgument, - fmt.Sprintf("[%s] resourceConfigApiKey missing in secret, cannot set quota limit for bucket", reqID)) + "resourceConfigApiKey missing in secret, cannot set quota limit for bucket") } quotaBytes := req.GetCapacityRange().GetRequiredBytes() if quotaBytes <= 0 { logger.Error(ctx, cs.Logger, "Invalid storage size for quota limit", zap.Int64("bytes", quotaBytes)) return nil, status.Error(codes.InvalidArgument, - fmt.Sprintf("[%s] enable quotaLimit requested but no positive storage size requested in PVC", reqID)) + "enable quotaLimit requested but no positive storage size requested in PVC") } logger.Info(ctx, cs.Logger, "Quota limit enabled", zap.Int64("quota_bytes", quotaBytes)) } @@ -194,7 +192,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } if endPoint == "" { logger.Error(ctx, cs.Logger, "COS endpoint not specified") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] cosEndpoint unknown", reqID)) + return nil, status.Error(codes.InvalidArgument, "cosEndpoint unknown") } locationConstraint = secretMap["locationConstraint"] @@ -205,7 +203,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol } if locationConstraint == "" { logger.Error(ctx, cs.Logger, "Location constraint not specified") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] locationConstraint unknown", reqID)) + return nil, status.Error(codes.InvalidArgument, "locationConstraint unknown") } kpRootKeyCrn = secretMap["kpRootKeyCRN"] @@ -228,7 +226,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol enable := strings.ToLower(strings.TrimSpace(val)) if enable != "true" && enable != "false" { logger.Error(ctx, cs.Logger, "Invalid bucket versioning value in secret", zap.String("value", val)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Invalid BucketVersioning value in secret: %s. Value set %s. Must be 'true' or 'false'", reqID, customSecretName, val)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Invalid BucketVersioning value in secret: %s. Value set %s. Must be 'true' or 'false'", customSecretName, val)) } bucketVersioning = enable logger.Info(ctx, cs.Logger, "Bucket versioning from secret", zap.String("versioning", bucketVersioning)) @@ -237,7 +235,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if enable != "true" && enable != "false" { logger.Error(ctx, cs.Logger, "Invalid bucket versioning value in storage class", zap.String("value", val)) return nil, status.Error(codes.InvalidArgument, - fmt.Sprintf("[%s] Invalid bucketVersioning value in storage class: %s. Must be 'true' or 'false'", reqID, val)) + fmt.Sprintf("Invalid bucketVersioning value in storage class: %s. Must be 'true' or 'false'", val)) } bucketVersioning = enable logger.Info(ctx, cs.Logger, "Bucket versioning from storage class", zap.String("versioning", bucketVersioning)) @@ -246,7 +244,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol creds, err := getObjectStorageCredentialsFromSecret(ctx, secretMap, cs.iamEndpoint, cs.Logger) if err != nil { logger.Error(ctx, cs.Logger, "Error getting credentials from secret", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in getting credentials %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in getting credentials: %v", err)) } logger.Info(ctx, cs.Logger, "Creating object storage session", zap.String("endpoint", endPoint), @@ -265,7 +263,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if err != nil { logger.Error(ctx, cs.Logger, "Failed to create bucket", zap.String("bucket_name", bucketName), zap.Error(err)) - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] %v: %v", reqID, err, bucketName)) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("%v:: %v", err, bucketName)) } params["userProvidedBucket"] = "false" logger.Info(ctx, cs.Logger, "Created bucket successfully", zap.String("bucket_name", bucketName)) @@ -287,7 +285,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol zap.String("bucket_name", bucketName), zap.Error(delErr)) } } - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set bucket quota limit: %v", reqID, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set bucket quota limit:: %v", err)) } logger.Info(ctx, cs.Logger, "Successfully applied hard quota to bucket", zap.Int64("quota_bytes", quotaBytes), zap.String("bucket_name", bucketName)) @@ -307,10 +305,10 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if err1 != nil { logger.Error(ctx, cs.Logger, "Failed to delete bucket after versioning failure", zap.String("bucket_name", bucketName), zap.Error(err1)) - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] cannot set versioning: %v and cannot delete bucket %s: %v", reqID, err, bucketName, err1)) + return nil, status.Error(codes.Internal, fmt.Sprintf("cannot set versioning: %v and cannot delete bucket %s:: %v", err, bucketName, err1)) } } - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set versioning %t for bucket %s: %v", reqID, enable, bucketName, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set versioning %t for bucket %s:: %v", enable, bucketName, err)) } logger.Info(ctx, cs.Logger, "Bucket versioning set successfully", zap.Bool("enable", enable), zap.String("bucket_name", bucketName)) @@ -323,14 +321,14 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol tempBucketName := getTempBucketName(ctx, mounter, volumeID, cs.Logger) if tempBucketName == "" { logger.Error(ctx, cs.Logger, "Unable to generate temp bucket name") - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] Unable to access the bucket: %v", reqID, tempBucketName)) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Unable to access the bucket:: %v", tempBucketName)) } logger.Info(ctx, cs.Logger, "Creating temp bucket", zap.String("temp_bucket_name", tempBucketName)) err = createBucket(ctx, sess, tempBucketName, kpRootKeyCrn, cs.Logger) if err != nil { logger.Error(ctx, cs.Logger, "Failed to create temp bucket", zap.String("temp_bucket_name", tempBucketName), zap.Error(err)) - return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("[%s] %v: %v", reqID, err, tempBucketName)) + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("%v:: %v", err, tempBucketName)) } if quotaLimitEnabled { @@ -347,7 +345,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol logger.Error(ctx, cs.Logger, "Failed to delete temp bucket after quota limit failure", zap.String("temp_bucket_name", tempBucketName), zap.Error(delErr)) } - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set bucket quota limit: %v", reqID, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set bucket quota limit:: %v", err)) } logger.Info(ctx, cs.Logger, "Successfully applied hard quota to temp bucket", zap.Int64("quota_bytes", quotaBytes), zap.String("temp_bucket_name", tempBucketName)) @@ -366,9 +364,9 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol if err1 != nil { logger.Error(ctx, cs.Logger, "Failed to delete temp bucket after versioning failure", zap.String("temp_bucket_name", tempBucketName), zap.Error(err1)) - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] cannot set versioning: %v and cannot delete temp bucket %s: %v", reqID, err, tempBucketName, err1)) + return nil, status.Error(codes.Internal, fmt.Sprintf("cannot set versioning: %v and cannot delete temp bucket %s:: %v", err, tempBucketName, err1)) } - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] failed to set versioning %t for temp bucket %s: %v", reqID, enable, tempBucketName, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to set versioning %t for temp bucket %s:: %v", enable, tempBucketName, err)) } logger.Info(ctx, cs.Logger, "Temp bucket versioning set successfully", zap.Bool("enable", enable), zap.String("temp_bucket_name", tempBucketName)) @@ -394,12 +392,11 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { // Extract request ID from context - reqID := requestid.FromContext(ctx) volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, cs.Logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } logger.Info(ctx, cs.Logger, "DeleteVolume started", zap.String("volume_id", volumeID)) @@ -407,7 +404,7 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { logger.Error(ctx, cs.Logger, "Error modifying request", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in modifying requests: %v", err)) } logger.Debug(ctx, cs.Logger, "DeleteVolume request details", zap.Any("request", modifiedRequest.(*csi.DeleteVolumeRequest))) @@ -433,7 +430,7 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol if secretName == "" { logger.Error(ctx, cs.Logger, "Secret details not found in PV") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret details not found, could not fetch the secret", reqID)) + return nil, status.Error(codes.InvalidArgument, "Secret details not found, could not fetch the secret") } if secretNamespace == "" { @@ -451,7 +448,7 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol secret, err := cs.Stats.GetSecret(secretName, secretNamespace) if err != nil { logger.Error(ctx, cs.Logger, "Secret resource not found", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Secret resource not found %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Secret resource not found: %v", err)) } secretMapCustom := parseCustomSecret(ctx, secret, cs.Logger) @@ -462,7 +459,7 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol creds, err := getObjectStorageCredentialsFromSecret(ctx, secretMap, cs.iamEndpoint, cs.Logger) if err != nil { logger.Error(ctx, cs.Logger, "Error getting credentials from secret", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in getting credentials %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in getting credentials: %v", err)) } logger.Info(ctx, cs.Logger, "Creating object storage session for deletion", @@ -496,23 +493,20 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol } func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ControllerPublishVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerPublishVolume not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerPublishVolume", reqID)) + return nil, status.Error(codes.Unimplemented, "ControllerPublishVolume") } func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ControllerUnpublishVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerUnpublishVolume not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerUnpublishVolume", reqID)) + return nil, status.Error(codes.Unimplemented, "ControllerUnpublishVolume") } func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) { - reqID := requestid.FromContext(ctx) logger.Info(ctx, cs.Logger, "ValidateVolumeCapabilities started") logger.Debug(ctx, cs.Logger, "ValidateVolumeCapabilities request", zap.Any("request", req)) @@ -521,13 +515,13 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, cs.Logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } volCaps := req.GetVolumeCapabilities() if len(volCaps) == 0 { logger.Error(ctx, cs.Logger, "Volume capabilities missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capabilities missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume capabilities missing in request") } var confirmed *csi.ValidateVolumeCapabilitiesResponse_Confirmed @@ -545,19 +539,17 @@ func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req } func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ListVolumes request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ListVolumes not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListVolumes", reqID)) + return nil, status.Error(codes.Unimplemented, "ListVolumes") } func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "GetCapacity request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "GetCapacity not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] GetCapacity", reqID)) + return nil, status.Error(codes.Unimplemented, "GetCapacity") } func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { @@ -581,51 +573,45 @@ func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req * } func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "CreateSnapshot request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "CreateSnapshot not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] CreateSnapshot", reqID)) + return nil, status.Error(codes.Unimplemented, "CreateSnapshot") } func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "DeleteSnapshot request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "DeleteSnapshot not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] DeleteSnapshot", reqID)) + return nil, status.Error(codes.Unimplemented, "DeleteSnapshot") } func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ListSnapshots request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ListSnapshots not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ListSnapshots", reqID)) + return nil, status.Error(codes.Unimplemented, "ListSnapshots") } func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ControllerExpandVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerExpandVolume not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerExpandVolume", reqID)) + return nil, status.Error(codes.Unimplemented, "ControllerExpandVolume") } func (cs *controllerServer) ControllerGetVolume(ctx context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ControllerGetVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerGetVolume not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerGetVolume", reqID)) + return nil, status.Error(codes.Unimplemented, "ControllerGetVolume") } func (cs *controllerServer) ControllerModifyVolume(ctx context.Context, req *csi.ControllerModifyVolumeRequest) (*csi.ControllerModifyVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Debug(ctx, cs.Logger, "ControllerModifyVolume request", zap.Any("request", req)) logger.Info(ctx, cs.Logger, "ControllerModifyVolume not implemented") - return nil, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] ControllerModifyVolume", reqID)) + return nil, status.Error(codes.Unimplemented, "ControllerModifyVolume") } func getObjectStorageCredentialsFromSecret(ctx context.Context, secretMap map[string]string, iamEP string, log *zap.Logger) (*s3client.ObjectStorageCredentials, error) { diff --git a/pkg/driver/controllerserver_test.go b/pkg/driver/controllerserver_test.go index 7702569a..1d0543d7 100644 --- a/pkg/driver/controllerserver_test.go +++ b/pkg/driver/controllerserver_test.go @@ -407,7 +407,7 @@ func TestCreateVolume(t *testing.T) { }, }), expectedResp: nil, - expectedErr: errors.New("[test-request-id] secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations"), + expectedErr: errors.New("secretName annotation 'cos.csi.driver/secret' not specified in the PVC annotations"), }, { testCaseName: "Negative: Secret and PVC Names Different, Failed to get Secret", @@ -566,7 +566,7 @@ func TestCreateVolume(t *testing.T) { driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, expectedErr: status.Error(codes.InvalidArgument, - "[test-request-id] resourceConfigApiKey missing in secret, cannot set quota limit for bucket"), + "resourceConfigApiKey missing in secret, cannot set quota limit for bucket"), }, { @@ -589,7 +589,7 @@ func TestCreateVolume(t *testing.T) { cosSession: &s3client.FakeCOSSessionFactory{}, driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, - expectedErr: status.Error(codes.InvalidArgument, `[test-request-id] invalid quotaLimit value "yes": must be 'true' or 'false'`), + expectedErr: status.Error(codes.InvalidArgument, `invalid quotaLimit value "yes": must be 'true' or 'false'`), }, { testCaseName: "Negative: quotaLimit=true with zero capacity (direct secrets)", @@ -612,7 +612,7 @@ func TestCreateVolume(t *testing.T) { cosSession: &s3client.FakeCOSSessionFactory{}, driverStatsUtils: utils.NewFakeStatsUtilsImpl(utils.FakeStatsUtilsFuncStruct{}), expectedResp: nil, - expectedErr: status.Error(codes.InvalidArgument, "[test-request-id] enable quotaLimit requested but no positive storage size requested in PVC"), + expectedErr: status.Error(codes.InvalidArgument, "enable quotaLimit requested but no positive storage size requested in PVC"), }, { testCaseName: "Positive: quotaLimit=true with positive capacity (direct secrets)", diff --git a/pkg/driver/nodeserver.go b/pkg/driver/nodeserver.go index 5883108c..2cb5609c 100644 --- a/pkg/driver/nodeserver.go +++ b/pkg/driver/nodeserver.go @@ -18,7 +18,6 @@ import ( "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/IBM/ibm-object-csi-driver/pkg/mounter" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" - "github.com/IBM/ibm-object-csi-driver/pkg/requestid" "github.com/IBM/ibm-object-csi-driver/pkg/utils" "github.com/container-storage-interface/spec/lib/go/csi" "go.uber.org/zap" @@ -45,7 +44,6 @@ type NodeServerConfig struct { } func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Info(ctx, ns.logger, "NodeStageVolume started") logger.Debug(ctx, ns.logger, "NodeStageVolume request", zap.Any("request", req)) @@ -53,13 +51,13 @@ func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } stagingTargetPath := req.GetStagingTargetPath() if len(stagingTargetPath) == 0 { logger.Error(ctx, ns.logger, "Target path missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } logger.Info(ctx, ns.logger, "NodeStageVolume completed", @@ -69,7 +67,6 @@ func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol } func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Info(ctx, ns.logger, "NodeUnstageVolume started") logger.Debug(ctx, ns.logger, "NodeUnstageVolume request", zap.Any("request", req)) @@ -77,13 +74,13 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } stagingTargetPath := req.GetStagingTargetPath() if len(stagingTargetPath) == 0 { logger.Error(ctx, ns.logger, "Target path missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } logger.Info(ctx, ns.logger, "NodeUnstageVolume completed", @@ -93,18 +90,17 @@ func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag } func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { - reqID := requestid.FromContext(ctx) volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } targetPath := req.GetTargetPath() if len(targetPath) == 0 { logger.Error(ctx, ns.logger, "Target path missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } logger.Info(ctx, ns.logger, "NodePublishVolume started", @@ -114,7 +110,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis modifiedRequest, err := utils.ReplaceAndReturnCopy(req) if err != nil { logger.Error(ctx, ns.logger, "Error modifying request", zap.Error(err)) - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Error in modifying requests %v", reqID, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("Error in modifying requests: %v", err)) } logger.Debug(ctx, ns.logger, "NodePublishVolume request", zap.Any("request", modifiedRequest.(*csi.NodePublishVolumeRequest))) @@ -123,7 +119,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis if req.GetVolumeCapability() == nil { logger.Error(ctx, ns.logger, "Volume capability missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume capability missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request") } logger.Info(ctx, ns.logger, "Checking mount point", zap.String("target_path", targetPath)) @@ -131,7 +127,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis if err != nil { logger.Error(ctx, ns.logger, "Cannot validate target mount point", zap.String("target_path", targetPath), zap.Error(err)) - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) + return nil, status.Error(codes.Internal, fmt.Sprintf("%v", err.Error())) } deviceID := "" @@ -180,7 +176,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis if len(secretMap["cosEndpoint"]) == 0 { logger.Error(ctx, ns.logger, "S3 Service endpoint not provided") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] S3 Service endpoint not provided", reqID)) + return nil, status.Error(codes.InvalidArgument, "S3 Service endpoint not provided") } if len(secretMap["iamEndpoint"]) == 0 { @@ -194,12 +190,12 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis tempBucketName, err := ns.Stats.GetBucketNameFromPV(volumeID) if err != nil { logger.Error(ctx, ns.logger, "Unable to fetch PV", zap.String("volume_id", volumeID), zap.Error(err)) - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) + return nil, status.Error(codes.Internal, fmt.Sprintf("%v", err.Error())) } if tempBucketName == "" { logger.Error(ctx, ns.logger, "Unable to fetch bucket name from PV") - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] unable to fetch bucket name from pv", reqID)) + return nil, status.Error(codes.Internal, "unable to fetch bucket name from pv") } secretMap["bucketName"] = tempBucketName @@ -229,18 +225,17 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis } func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { - reqID := requestid.FromContext(ctx) volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } targetPath := req.GetTargetPath() if len(targetPath) == 0 { logger.Error(ctx, ns.logger, "Target path missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Target path missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } logger.Info(ctx, ns.logger, "NodeUnpublishVolume started", @@ -253,7 +248,7 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu attrib, err := ns.Stats.GetPVAttributes(volumeID) if err != nil { logger.Error(ctx, ns.logger, "Failed to get PV details", zap.String("volume_id", volumeID), zap.Error(err)) - return nil, status.Error(codes.NotFound, fmt.Sprintf("[%s] Failed to get PV details", reqID)) + return nil, status.Error(codes.NotFound, "Failed to get PV details") } mounterObj := ns.Mounter.NewMounter(attrib, nil, nil, nil) @@ -262,7 +257,7 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu if err = mounterObj.Unmount(ctx, targetPath); err != nil { //TODO: Need to handle the case with non existing mount separately - https://github.com/IBM/ibm-object-csi-driver/issues/46 logger.Error(ctx, ns.logger, "Unmount failed", zap.String("target_path", targetPath), zap.Error(err)) - return nil, status.Error(codes.Internal, fmt.Sprintf("[%s] %v", reqID, err.Error())) + return nil, status.Error(codes.Internal, fmt.Sprintf("%v", err.Error())) } logger.Info(ctx, ns.logger, "NodeUnpublishVolume completed successfully", @@ -272,7 +267,6 @@ func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu } func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { - reqID := requestid.FromContext(ctx) logger.Info(ctx, ns.logger, "NodeGetVolumeStats started") logger.Debug(ctx, ns.logger, "NodeGetVolumeStats request", zap.Any("request", req)) @@ -280,13 +274,13 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo volumeID := req.GetVolumeId() if len(volumeID) == 0 { logger.Error(ctx, ns.logger, "Volume ID missing in request") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Volume ID missing in request", reqID)) + return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } volumePath := req.VolumePath if volumePath == "" { logger.Error(ctx, ns.logger, "Volume path doesn't exist") - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("[%s] Path Doesn't exist", reqID)) + return nil, status.Error(codes.InvalidArgument, "Path Doesn't exist") } logger.Debug(ctx, ns.logger, "Getting filesystem stats", zap.String("volume_path", volumePath)) @@ -299,7 +293,7 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo return &csi.NodeGetVolumeStatsResponse{ VolumeCondition: &csi.VolumeCondition{ Abnormal: true, - Message: fmt.Sprintf("[%s] %v", reqID, err.Error()), + Message: fmt.Sprintf("%v", err.Error()), }, }, nil } @@ -352,10 +346,9 @@ func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVo } func (ns *nodeServer) NodeExpandVolume(ctx context.Context, _ *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { - reqID := requestid.FromContext(ctx) logger.Info(ctx, ns.logger, "NodeExpandVolume not implemented") - return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, fmt.Sprintf("[%s] NodeExpandVolume is not implemented", reqID)) + return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, "NodeExpandVolume is not implemented") } func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { diff --git a/pkg/driver/nodeserver_test.go b/pkg/driver/nodeserver_test.go index ae876151..f226ab38 100644 --- a/pkg/driver/nodeserver_test.go +++ b/pkg/driver/nodeserver_test.go @@ -545,7 +545,7 @@ func TestNodeGetVolumeStats(t *testing.T) { expectedResp: &csi.NodeGetVolumeStatsResponse{ VolumeCondition: &csi.VolumeCondition{ Abnormal: true, - Message: "[test-request-id] transpoint endpoint is not connected", + Message: "transpoint endpoint is not connected", }, }, expectedErr: nil, From 440ab069f36f5e7d24705ef61e6b72d759cd640c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 23:38:49 +0530 Subject: [PATCH 38/64] log fixes --- cmd/main.go | 2 +- cos-csi-mounter/server/server.go | 30 +++++++++--------- pkg/logger/factory.go | 51 ++++++++++++++++++++++++++++++ pkg/mounter/mounter-rclone.go | 14 ++------ pkg/mounter/mounter-s3fs.go | 14 ++------ pkg/mounter/utils/mounter_utils.go | 8 ++--- pkg/utils/driver_utils.go | 8 ++--- 7 files changed, 77 insertions(+), 50 deletions(-) create mode 100644 pkg/logger/factory.go diff --git a/cmd/main.go b/cmd/main.go index cff25df3..f6a6cc0f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -66,7 +66,7 @@ func getZapLogger() *zap.Logger { encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder logger := zap.New(zapcore.NewCore( - zapcore.NewJSONEncoder(encoderCfg), + zapcore.NewConsoleEncoder(encoderCfg), zapcore.Lock(os.Stdout), atom, ), zap.AddCaller()).With(zap.String("name", config.CSIPluginGithubName)).With(zap.String("CSIDriverName", "IBM CSI Object Driver")) diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index ed226aa2..30b78f90 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -52,7 +52,7 @@ func setUpLogger() *zap.Logger { encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder logger := zap.New(zapcore.NewCore( - zapcore.NewJSONEncoder(encoderCfg), + zapcore.NewConsoleEncoder(encoderCfg), zapcore.Lock(os.Stdout), atom, ), zap.AddCaller()).With(zap.String("ServiceName", "cos-csi-mounter")) @@ -172,50 +172,50 @@ func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) var request MountRequest if err := c.BindJSON(&request); err != nil { - log.Error(fmt.Sprintf("[%s] Invalid request", reqID), zap.Error(err)) + log.Error("Invalid request", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid request", reqID)}) return } - log.Info(fmt.Sprintf("[%s] New mount request", reqID), + log.Info("New mount request", zap.String("bucket", request.Bucket), zap.String("path", request.Path), zap.String("mounter", request.Mounter), zap.Any("args", request.Args)) if request.Mounter != constants.S3FS && request.Mounter != constants.RClone { - log.Error(fmt.Sprintf("[%s] Invalid mounter", reqID), zap.String("mounter", request.Mounter)) + log.Error("Invalid mounter", zap.String("mounter", request.Mounter)) c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid mounter", reqID)}) return } if request.Bucket == "" { - log.Error(fmt.Sprintf("[%s] Missing bucket in request", reqID)) + log.Error("Missing bucket in request") c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] missing bucket", reqID)}) return } // validate mounter args - log.Debug(fmt.Sprintf("[%s] Parsing mounter args", reqID)) + log.Debug("Parsing mounter args") args, err := parser.Parse(request) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to parse mounter args", reqID), + log.Error("Failed to parse mounter args", zap.String("mounter", request.Mounter), zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid args for mounter: %v", reqID, err)}) return } - log.Info(fmt.Sprintf("[%s] Mounting bucket", reqID), + log.Info("Mounting bucket", zap.String("path", request.Path), zap.String("mounter", request.Mounter)) err = mounter.FuseMount(request.Path, request.Mounter, args) if err != nil { - log.Error(fmt.Sprintf("[%s] Mount failed", reqID), zap.Error(err)) + log.Error("Mount failed", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("[%s] mount failed: %v", reqID, err)}) return } - log.Info(fmt.Sprintf("[%s] Bucket mount successful", reqID), + log.Info("Bucket mount successful", zap.String("bucket", request.Bucket), zap.String("path", request.Path)) c.JSON(http.StatusOK, gin.H{"status": "success"}) @@ -236,22 +236,22 @@ func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { } if err := c.BindJSON(&request); err != nil { - log.Error(fmt.Sprintf("[%s] Invalid request", reqID), zap.Error(err)) + log.Error("Invalid request", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("[%s] invalid request", reqID)}) return } - log.Info(fmt.Sprintf("[%s] New unmount request", reqID), zap.String("path", request.Path)) + log.Info("New unmount request", zap.String("path", request.Path)) - log.Info(fmt.Sprintf("[%s] Unmounting bucket", reqID), zap.String("path", request.Path)) + log.Info("Unmounting bucket", zap.String("path", request.Path)) err := mounter.FuseUnmount(request.Path) if err != nil { - log.Error(fmt.Sprintf("[%s] Unmount failed", reqID), zap.Error(err)) + log.Error("Unmount failed", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("[%s] unmount failed: %v", reqID, err)}) return } - log.Info(fmt.Sprintf("[%s] Bucket unmount successful", reqID), zap.String("path", request.Path)) + log.Info("Bucket unmount successful", zap.String("path", request.Path)) c.JSON(http.StatusOK, gin.H{"status": "success"}) } } diff --git a/pkg/logger/factory.go b/pkg/logger/factory.go new file mode 100644 index 00000000..a6adb3d0 --- /dev/null +++ b/pkg/logger/factory.go @@ -0,0 +1,51 @@ +/******************************************************************************* + * IBM Confidential + * OCO Source Materials + * IBM Cloud Kubernetes Service, 5737-D43 + * (C) Copyright IBM Corp. 2023 All Rights Reserved. + * The source code for this program is not published or otherwise divested of + * its trade secrets, irrespective of what has been deposited with + * the U.S. Copyright Office. + ******************************************************************************/ + +// Package logger provides logging utilities for the CSI driver +package logger + +import ( + "os" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// NewConsoleLogger creates a new zap logger with console encoding +// This provides human-readable logs with structured fields +func NewConsoleLogger(serviceName string) (*zap.Logger, error) { + atom := zap.NewAtomicLevel() + encoderCfg := zap.NewProductionEncoderConfig() + encoderCfg.TimeKey = "timestamp" + encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder + + logger := zap.New(zapcore.NewCore( + zapcore.NewConsoleEncoder(encoderCfg), + zapcore.Lock(os.Stdout), + atom, + ), zap.AddCaller()) + + if serviceName != "" { + logger = logger.With(zap.String("service", serviceName)) + } + + atom.SetLevel(zap.InfoLevel) + return logger, nil +} + +// NewConsoleLoggerOrNop creates a console logger or returns a no-op logger on error +// This is useful for init() functions where error handling is limited +func NewConsoleLoggerOrNop(serviceName string) *zap.Logger { + logger, err := NewConsoleLogger(serviceName) + if err != nil { + return zap.NewNop() + } + return logger +} diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index 9800cd41..ffc6fe74 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -65,12 +65,7 @@ var ( ) func init() { - var err error - rcloneLogger, err = zap.NewProduction() - if err != nil { - // Fallback to no-op logger if production logger fails - rcloneLogger = zap.NewNop() - } + rcloneLogger = logger.NewConsoleLoggerOrNop("rclone-mounter") } func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { @@ -140,11 +135,8 @@ func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounte mounter.MounterUtils = mounterUtils - // Initialize logger - use production logger or fallback to nop - mounter.logger, _ = zap.NewProduction() - if mounter.logger == nil { - mounter.logger = zap.NewNop() - } + // Initialize logger - use console logger or fallback to nop + mounter.logger = logger.NewConsoleLoggerOrNop("rclone-mounter") return mounter } diff --git a/pkg/mounter/mounter-s3fs.go b/pkg/mounter/mounter-s3fs.go index 89ec819d..cb1a1442 100644 --- a/pkg/mounter/mounter-s3fs.go +++ b/pkg/mounter/mounter-s3fs.go @@ -60,12 +60,7 @@ var ( ) func init() { - var err error - s3fsLogger, err = zap.NewProduction() - if err != nil { - // Fallback to no-op logger if production logger fails - s3fsLogger = zap.NewNop() - } + s3fsLogger = logger.NewConsoleLoggerOrNop("s3fs-mounter") } func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils, defaultParams map[string]string) Mounter { @@ -121,11 +116,8 @@ func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterU mounter.MounterUtils = mounterUtils - // Initialize logger - use production logger or fallback to nop - mounter.logger, _ = zap.NewProduction() - if mounter.logger == nil { - mounter.logger = zap.NewNop() - } + // Initialize logger - use console logger or fallback to nop + mounter.logger = logger.NewConsoleLoggerOrNop("s3fs-mounter") return mounter } diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index 61eadd92..042de091 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -14,6 +14,7 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/mitchellh/go-ps" "go.uber.org/zap" k8sMountUtils "k8s.io/mount-utils" @@ -28,12 +29,7 @@ var ErrTimeoutWaitProcess = errors.New("timeout waiting for process to end") var mounterUtilLogger *zap.Logger func init() { - var err error - mounterUtilLogger, err = zap.NewProduction() - if err != nil { - // Fallback to no-op logger if production logger fails - mounterUtilLogger = zap.NewNop() - } + mounterUtilLogger = logger.NewConsoleLoggerOrNop("mounter-utils") } type MounterUtils interface { diff --git a/pkg/utils/driver_utils.go b/pkg/utils/driver_utils.go index 7be7fdf5..df37894e 100644 --- a/pkg/utils/driver_utils.go +++ b/pkg/utils/driver_utils.go @@ -11,6 +11,7 @@ import ( "github.com/IBM/go-sdk-core/v5/core" rc "github.com/IBM/ibm-cos-sdk-go-config/v2/resourceconfigurationv1" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + "github.com/IBM/ibm-object-csi-driver/pkg/logger" "github.com/container-storage-interface/spec/lib/go/csi" "go.uber.org/zap" "google.golang.org/protobuf/proto" @@ -25,12 +26,7 @@ import ( var utilLogger *zap.Logger func init() { - var err error - utilLogger, err = zap.NewProduction() - if err != nil { - // Fallback to no-op logger if production logger fails - utilLogger = zap.NewNop() - } + utilLogger = logger.NewConsoleLoggerOrNop("driver-utils") } type StatsUtils interface { From cef91eee2312c08e82e60ba78d893db00ec979bc Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 11 Jun 2026 23:55:08 +0530 Subject: [PATCH 39/64] log fix --- cmd/main.go | 1 + cos-csi-mounter/server/server.go | 1 + pkg/logger/factory.go | 1 + 3 files changed, 3 insertions(+) diff --git a/cmd/main.go b/cmd/main.go index f6a6cc0f..f89e0b35 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -64,6 +64,7 @@ func getZapLogger() *zap.Logger { encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.TimeKey = "timestamp" encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder + encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder logger := zap.New(zapcore.NewCore( zapcore.NewConsoleEncoder(encoderCfg), diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index 30b78f90..b5e6359b 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -50,6 +50,7 @@ func setUpLogger() *zap.Logger { encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.TimeKey = "timestamp" encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder + encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder logger := zap.New(zapcore.NewCore( zapcore.NewConsoleEncoder(encoderCfg), diff --git a/pkg/logger/factory.go b/pkg/logger/factory.go index a6adb3d0..42cd3d9e 100644 --- a/pkg/logger/factory.go +++ b/pkg/logger/factory.go @@ -25,6 +25,7 @@ func NewConsoleLogger(serviceName string) (*zap.Logger, error) { encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.TimeKey = "timestamp" encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder + encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder logger := zap.New(zapcore.NewCore( zapcore.NewConsoleEncoder(encoderCfg), From 128a45c1422805062c251b8777e151791f338914 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sat, 13 Jun 2026 14:41:44 +0530 Subject: [PATCH 40/64] update logs --- .github/workflows/release.yml | 13 ++++++------- cos-csi-mounter/Makefile | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fda02cad..73943385 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: CI & Release on: push: branches: - - main + - ogging-add-reqid pull_request: branches: - main @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 1.0.5 + APP_VERSION: 0.12.32 steps: - name: Checkout Code @@ -139,13 +139,12 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: v1.0.5 - name: v1.0.5 + tag_name: 0.12.32 + name: 0.12.32 body: | ## 🚀 What’s New - - Fix for rclone mount hang issue - - Add support for s3fs disable_noobj_cache flag - - Skip unmount for 'is not a mountpoint' error + - updated logging method + - introduced requestID in logs prerelease: ${{ env.IS_LATEST_RELEASE != 'true' }} - name: Perform CodeQL Analysis diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 55da3103..0c9ee761 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 1.0.5 +APP_VERSION := 0.12.32 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 6e2b25d39eadd9c713eee84aa828ab6be052e377 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sat, 13 Jun 2026 15:13:32 +0530 Subject: [PATCH 41/64] publish .33 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 73943385..edce368e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.32 + APP_VERSION: 0.12.33 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.32 - name: 0.12.32 + tag_name: 0.12.33 + name: 0.12.33 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 0c9ee761..2ae40d57 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.32 +APP_VERSION := 0.12.33 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From d44c98effb291369210f62c82983b53a984f545a Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sat, 13 Jun 2026 15:33:36 +0530 Subject: [PATCH 42/64] testing logging changes --- .github/workflows/release.yml | 8 ++++---- cos-csi-mounter/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index edce368e..51f8f859 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: CI & Release on: push: branches: - - ogging-add-reqid + - logging-add-reqid pull_request: branches: - main @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.33 + APP_VERSION: 0.12.32 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.33 - name: 0.12.33 + tag_name: 0.12.32 + name: 0.12.32 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 2ae40d57..0c9ee761 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.33 +APP_VERSION := 0.12.32 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 5d700211a15903bd6b714b38c3d7a669ff894cfc Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sat, 13 Jun 2026 15:57:33 +0530 Subject: [PATCH 43/64] update version to v0.12.33 for log testing --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 51f8f859..878fd3a6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.32 + APP_VERSION: 0.12.33 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.32 - name: 0.12.32 + tag_name: 0.12.33 + name: 0.12.33 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 0c9ee761..2ae40d57 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.32 +APP_VERSION := 0.12.33 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From a1edcbe5a6efbc488bd01086517511de1a655d73 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sat, 13 Jun 2026 16:20:08 +0530 Subject: [PATCH 44/64] publish v0.12.33 --- cos-csi-mounter/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 2ae40d57..107d071a 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.33 +APP_VERSION := 0.12.33 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin @@ -107,3 +107,5 @@ clean: packages: packages: deb-build rpm-build tar-package clean + +#testing \ No newline at end of file From 4a8e4dcc03392374876ce5f549d9f533971832f7 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sun, 14 Jun 2026 21:17:23 +0530 Subject: [PATCH 45/64] testing logging --- cos-csi-mounter/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 107d071a..4006a45f 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.33 +APP_VERSION := 0.12.34 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From a5e5bf4341460a64a8b022f0fbf1473f24ade193 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Sun, 14 Jun 2026 21:21:34 +0530 Subject: [PATCH 46/64] publish v0.12.34 --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 878fd3a6..c9445d6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: CI & Release on: push: branches: - - logging-add-reqid + - logging-add-reqid-34 pull_request: branches: - main @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.33 + APP_VERSION: 0.12.34 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.33 - name: 0.12.33 + tag_name: 0.12.34 + name: 0.12.34 body: | ## 🚀 What’s New - updated logging method From 2e8be923b32df421548a17426de1375239be9d30 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Mon, 15 Jun 2026 10:18:19 +0530 Subject: [PATCH 47/64] publish v0.12.35 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9445d6a..47d5c8b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.34 + APP_VERSION: 0.12.35 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.34 - name: 0.12.34 + tag_name: 0.12.35 + name: 0.12.35 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 4006a45f..5f1e6026 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.34 +APP_VERSION := 0.12.35 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 4ef87bc0434b6a31174733bdd6dab98934dd27a1 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Mon, 15 Jun 2026 10:53:42 +0530 Subject: [PATCH 48/64] publish v0.12.36 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 47d5c8b7..2284b364 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.35 + APP_VERSION: v0.12.36 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.35 - name: 0.12.35 + tag_name: v0.12.36 + name: v0.12.36 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 5f1e6026..6b371e8f 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.35 +APP_VERSION := v0.12.36 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 8e8c9533675f762abd0f6bc62b8df0b317dd6e9c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 16 Jun 2026 17:48:33 +0530 Subject: [PATCH 49/64] end to end adding request id --- cmd/main.go | 13 ++-- cos-csi-mounter/server/fake_server.go | 9 +-- cos-csi-mounter/server/server.go | 33 +++++++--- cos-csi-mounter/server/server_test.go | 21 +++--- pkg/logger/factory.go | 57 +++++++++++++++- pkg/mounter/mounter-rclone.go | 4 +- pkg/mounter/mounter-rclone_test.go | 14 ++-- pkg/mounter/mounter-s3fs.go | 4 +- pkg/mounter/mounter-s3fs_test.go | 12 ++-- pkg/mounter/utils/fake_mounter_utils.go | 14 ++-- pkg/mounter/utils/mounter_utils.go | 88 +++++++++++++++---------- tests/sanity/sanity_test.go | 4 +- 12 files changed, 183 insertions(+), 90 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index f89e0b35..7a3acd7e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -59,18 +59,23 @@ func getOptions() *Options { } func getZapLogger() *zap.Logger { - // Prepare a new logger + // Prepare a new logger with standardized JSON format atom := zap.NewAtomicLevel() encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.TimeKey = "timestamp" encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder - encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder + encoderCfg.EncodeLevel = zapcore.LowercaseLevelEncoder + encoderCfg.MessageKey = "msg" + encoderCfg.CallerKey = "caller" + encoderCfg.LevelKey = "level" logger := zap.New(zapcore.NewCore( - zapcore.NewConsoleEncoder(encoderCfg), + zapcore.NewJSONEncoder(encoderCfg), zapcore.Lock(os.Stdout), atom, - ), zap.AddCaller()).With(zap.String("name", config.CSIPluginGithubName)).With(zap.String("CSIDriverName", "IBM CSI Object Driver")) + ), zap.AddCaller()).With( + zap.String("service", "ibm-object-csi-driver"), + zap.String("component", "csi-driver")) atom.SetLevel(zap.InfoLevel) return logger diff --git a/cos-csi-mounter/server/fake_server.go b/cos-csi-mounter/server/fake_server.go index d6b92610..b4e1efb5 100644 --- a/cos-csi-mounter/server/fake_server.go +++ b/cos-csi-mounter/server/fake_server.go @@ -4,6 +4,7 @@ package main import ( + "context" "errors" "net" "net/http" @@ -17,13 +18,13 @@ type MockMounterUtils struct { mock.Mock } -func (m *MockMounterUtils) FuseMount(path string, mounter string, args []string) error { - argsCalled := m.Called(path, mounter, args) +func (m *MockMounterUtils) FuseMount(ctx context.Context, path string, mounter string, args []string) error { + argsCalled := m.Called(ctx, path, mounter, args) return argsCalled.Error(0) } -func (m *MockMounterUtils) FuseUnmount(path string) error { - argsCalled := m.Called(path) +func (m *MockMounterUtils) FuseUnmount(ctx context.Context, path string) error { + argsCalled := m.Called(ctx, path) return argsCalled.Error(0) } diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index b5e6359b..bca8f15d 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -4,6 +4,7 @@ package main import ( + "context" "flag" "fmt" "net" @@ -16,6 +17,7 @@ import ( "time" "github.com/IBM/ibm-object-csi-driver/pkg/constants" + loggerPkg "github.com/IBM/ibm-object-csi-driver/pkg/logger" mounterUtils "github.com/IBM/ibm-object-csi-driver/pkg/mounter/utils" "github.com/gin-gonic/gin" "go.uber.org/zap" @@ -45,18 +47,23 @@ func init() { } func setUpLogger() *zap.Logger { - // Prepare a new logger + // Prepare a new logger with standardized JSON format atom := zap.NewAtomicLevel() encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.TimeKey = "timestamp" encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder - encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder + encoderCfg.EncodeLevel = zapcore.LowercaseLevelEncoder + encoderCfg.MessageKey = "msg" + encoderCfg.CallerKey = "caller" + encoderCfg.LevelKey = "level" logger := zap.New(zapcore.NewCore( - zapcore.NewConsoleEncoder(encoderCfg), + zapcore.NewJSONEncoder(encoderCfg), zapcore.Lock(os.Stdout), atom, - ), zap.AddCaller()).With(zap.String("ServiceName", "cos-csi-mounter")) + ), zap.AddCaller()).With( + zap.String("service", "cos-csi-mounter"), + zap.String("component", "mounter-server")) atom.SetLevel(zap.InfoLevel) return logger } @@ -163,10 +170,10 @@ func main() { func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) gin.HandlerFunc { return func(c *gin.Context) { - // Extract request ID from HTTP header + // Extract request ID from HTTP header or generate one reqID := c.GetHeader("X-Request-ID") if reqID == "" { - reqID = "unknown" + reqID = loggerPkg.GenerateRequestID() } log := logger.With(zap.String("request_id", reqID)) @@ -209,7 +216,10 @@ func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) log.Info("Mounting bucket", zap.String("path", request.Path), zap.String("mounter", request.Mounter)) - err = mounter.FuseMount(request.Path, request.Mounter, args) + + // Create context with request_id for end-to-end tracing + ctx := context.WithValue(c.Request.Context(), "request_id", reqID) + err = mounter.FuseMount(ctx, request.Path, request.Mounter, args) if err != nil { log.Error("Mount failed", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("[%s] mount failed: %v", reqID, err)}) @@ -225,10 +235,10 @@ func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { return func(c *gin.Context) { - // Extract request ID from HTTP header + // Extract request ID from HTTP header or generate one reqID := c.GetHeader("X-Request-ID") if reqID == "" { - reqID = "unknown" + reqID = loggerPkg.GenerateRequestID() } log := logger.With(zap.String("request_id", reqID)) @@ -245,7 +255,10 @@ func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { log.Info("New unmount request", zap.String("path", request.Path)) log.Info("Unmounting bucket", zap.String("path", request.Path)) - err := mounter.FuseUnmount(request.Path) + + // Create context with request_id for end-to-end tracing + ctx := context.WithValue(c.Request.Context(), "request_id", reqID) + err := mounter.FuseUnmount(ctx, request.Path) if err != nil { log.Error("Unmount failed", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("[%s] unmount failed: %v", reqID, err)}) diff --git a/cos-csi-mounter/server/server_test.go b/cos-csi-mounter/server/server_test.go index b7dcdc6f..c1d28dc5 100644 --- a/cos-csi-mounter/server/server_test.go +++ b/cos-csi-mounter/server/server_test.go @@ -19,6 +19,7 @@ import ( "github.com/IBM/ibm-object-csi-driver/pkg/constants" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestSetupSocket_CreatesSocket(t *testing.T) { @@ -235,7 +236,7 @@ func TestHandleCosMount_FuseMountFails(t *testing.T) { expectedArgs := []string{"--endpoint=https://s3.example.com"} mockParser.On("Parse", request).Return(expectedArgs, nil) - mockMounter.On("FuseMount", request.Path, request.Mounter, expectedArgs).Return(fmt.Errorf("mount error")) + mockMounter.On("FuseMount", mock.Anything, request.Path, request.Mounter, expectedArgs).Return(fmt.Errorf("mount error")) router := gin.Default() router.POST("/mount", handleCosMount(mockMounter, mockParser)) @@ -268,7 +269,7 @@ func TestHandleCosMount_Success(t *testing.T) { expectedArgs := []string{"--endpoint=https://s3.example.com"} mockParser.On("Parse", request).Return(expectedArgs, nil) - mockMounter.On("FuseMount", request.Path, request.Mounter, expectedArgs).Return(nil) + mockMounter.On("FuseMount", mock.Anything, request.Path, request.Mounter, expectedArgs).Return(nil) router := gin.Default() router.POST("/mount", handleCosMount(mockMounter, mockParser)) @@ -303,11 +304,11 @@ func TestHandleCosUnmount_InvalidJSON(t *testing.T) { } func TestHandleCosUnmount_UnmountFailure(t *testing.T) { - mock := new(MockMounterUtils) - mock.On("FuseUnmount", "/mnt/fail").Return(errors.New("mock failure")) + mockMounter := new(MockMounterUtils) + mockMounter.On("FuseUnmount", mock.Anything, "/mnt/fail").Return(errors.New("mock failure")) router := gin.Default() - router.POST("/unmount", handleCosUnmount(mock)) + router.POST("/unmount", handleCosUnmount(mockMounter)) reqBody := map[string]string{"path": "/mnt/fail"} body, _ := json.Marshal(reqBody) @@ -320,15 +321,15 @@ func TestHandleCosUnmount_UnmountFailure(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Contains(t, w.Body.String(), "unmount failed") - mock.AssertExpectations(t) + mockMounter.AssertExpectations(t) } func TestHandleCosUnmount_Success(t *testing.T) { - mock := new(MockMounterUtils) - mock.On("FuseUnmount", "/mnt/success").Return(nil) + mockMounter := new(MockMounterUtils) + mockMounter.On("FuseUnmount", mock.Anything, "/mnt/success").Return(nil) router := gin.Default() - router.POST("/unmount", handleCosUnmount(mock)) + router.POST("/unmount", handleCosUnmount(mockMounter)) reqBody := map[string]string{"path": "/mnt/success"} body, _ := json.Marshal(reqBody) @@ -341,5 +342,5 @@ func TestHandleCosUnmount_Success(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "success") - mock.AssertExpectations(t) + mockMounter.AssertExpectations(t) } diff --git a/pkg/logger/factory.go b/pkg/logger/factory.go index 42cd3d9e..359d2e67 100644 --- a/pkg/logger/factory.go +++ b/pkg/logger/factory.go @@ -12,20 +12,62 @@ package logger import ( + "crypto/rand" + "encoding/hex" "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) +// NewJSONLogger creates a new zap logger with JSON encoding for production +// This provides machine-readable structured logs with consistent formatting +func NewJSONLogger(serviceName string) (*zap.Logger, error) { + atom := zap.NewAtomicLevel() + encoderCfg := zap.NewProductionEncoderConfig() + encoderCfg.TimeKey = "timestamp" + encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder + encoderCfg.EncodeLevel = zapcore.LowercaseLevelEncoder + encoderCfg.MessageKey = "msg" + encoderCfg.CallerKey = "caller" + encoderCfg.LevelKey = "level" + + logger := zap.New(zapcore.NewCore( + zapcore.NewJSONEncoder(encoderCfg), + zapcore.Lock(os.Stdout), + atom, + ), zap.AddCaller()) + + if serviceName != "" { + logger = logger.With(zap.String("service", serviceName)) + } + + atom.SetLevel(zap.InfoLevel) + return logger, nil +} + +// NewJSONLoggerOrNop creates a JSON logger or returns a no-op logger on error +// This is useful for init() functions where error handling is limited +func NewJSONLoggerOrNop(serviceName string) *zap.Logger { + logger, err := NewJSONLogger(serviceName) + if err != nil { + return zap.NewNop() + } + return logger +} + // NewConsoleLogger creates a new zap logger with console encoding -// This provides human-readable logs with structured fields +// This provides human-readable logs with structured fields (for development/debugging) +// Deprecated: Use NewJSONLogger for production deployments func NewConsoleLogger(serviceName string) (*zap.Logger, error) { atom := zap.NewAtomicLevel() encoderCfg := zap.NewProductionEncoderConfig() encoderCfg.TimeKey = "timestamp" encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder - encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder + encoderCfg.EncodeLevel = zapcore.LowercaseLevelEncoder + encoderCfg.MessageKey = "msg" + encoderCfg.CallerKey = "caller" + encoderCfg.LevelKey = "level" logger := zap.New(zapcore.NewCore( zapcore.NewConsoleEncoder(encoderCfg), @@ -42,7 +84,7 @@ func NewConsoleLogger(serviceName string) (*zap.Logger, error) { } // NewConsoleLoggerOrNop creates a console logger or returns a no-op logger on error -// This is useful for init() functions where error handling is limited +// Deprecated: Use NewJSONLoggerOrNop for production deployments func NewConsoleLoggerOrNop(serviceName string) *zap.Logger { logger, err := NewConsoleLogger(serviceName) if err != nil { @@ -50,3 +92,12 @@ func NewConsoleLoggerOrNop(serviceName string) *zap.Logger { } return logger } + +// GenerateRequestID generates a unique request ID for tracing +func GenerateRequestID() string { + b := make([]byte, 16) + if _, err := rand.Read(b); err != nil { + return "unknown" + } + return hex.EncodeToString(b) +} diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index ffc6fe74..81c5b68c 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -243,7 +243,7 @@ func (rclone *RcloneMounter) Mount(ctx context.Context, source string, target st } logger.Info(ctx, rclone.logger, "NodeServer mounting") - err = rclone.MounterUtils.FuseMount(target, constants.RClone, args) + err = rclone.MounterUtils.FuseMount(ctx, target, constants.RClone, args) if err != nil { logger.Error(ctx, rclone.logger, "FuseMount failed", zap.Error(err)) } else { @@ -273,7 +273,7 @@ func (rclone *RcloneMounter) Unmount(ctx context.Context, target string) error { logger.Info(ctx, rclone.logger, "NodeServer unmounting") - err := rclone.MounterUtils.FuseUnmount(target) + err := rclone.MounterUtils.FuseUnmount(ctx, target) if err != nil { logger.Error(ctx, rclone.logger, "FuseUnmount failed", zap.Error(err)) return err diff --git a/pkg/mounter/mounter-rclone_test.go b/pkg/mounter/mounter-rclone_test.go index 94e110bb..c2ce4bd6 100644 --- a/pkg/mounter/mounter-rclone_test.go +++ b/pkg/mounter/mounter-rclone_test.go @@ -138,7 +138,7 @@ func TestRcloneMount_NodeServer_Positive(t *testing.T) { UID: "testUID", logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseMountFn: func(path, comm string, args []string) error { + FuseMountFn: func(ctx context.Context, path, comm string, args []string) error { return nil }, }), @@ -178,7 +178,7 @@ func TestRcloneMount_WorkerNode_Positive(t *testing.T) { ObjectPath: "testObjectPath", logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseMountFn: func(path, comm string, args []string) error { + FuseMountFn: func(ctx context.Context, path, comm string, args []string) error { return nil }, }), @@ -207,7 +207,7 @@ func TestRcloneMount_WorkerNode_Negative(t *testing.T) { ObjectPath: "testObjectPath", logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseMountFn: func(path, comm string, args []string) error { + FuseMountFn: func(ctx context.Context, path, comm string, args []string) error { return nil }, }), @@ -233,7 +233,7 @@ func TestRcloneUnmount_NodeServer(t *testing.T) { rclone := &RcloneMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return nil }, }), @@ -251,7 +251,7 @@ func TestRcloneUnmount_WorkerNode(t *testing.T) { rclone := &RcloneMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return nil }, })} @@ -270,7 +270,7 @@ func TestRcloneUnmount_WorkerNode_Negative(t *testing.T) { rclone := &RcloneMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return nil }, }), @@ -293,7 +293,7 @@ func TestRcloneUnmount_NodeServer_Negative(t *testing.T) { rclone := &RcloneMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return errors.New("failed to unmount") }, }), diff --git a/pkg/mounter/mounter-s3fs.go b/pkg/mounter/mounter-s3fs.go index cb1a1442..669bde93 100644 --- a/pkg/mounter/mounter-s3fs.go +++ b/pkg/mounter/mounter-s3fs.go @@ -199,7 +199,7 @@ func (s3fs *S3fsMounter) Mount(ctx context.Context, source string, target string } logger.Info(ctx, s3fs.logger, "NodeServer mounting") - err = s3fs.MounterUtils.FuseMount(target, constants.S3FS, args) + err = s3fs.MounterUtils.FuseMount(ctx, target, constants.S3FS, args) if err != nil { logger.Error(ctx, s3fs.logger, "FuseMount failed", zap.Error(err)) } else { @@ -229,7 +229,7 @@ func (s3fs *S3fsMounter) Unmount(ctx context.Context, target string) error { logger.Info(ctx, s3fs.logger, "NodeServer unmounting") - err := s3fs.MounterUtils.FuseUnmount(target) + err := s3fs.MounterUtils.FuseUnmount(ctx, target) if err != nil { logger.Error(ctx, s3fs.logger, "FuseUnmount failed", zap.Error(err)) return err diff --git a/pkg/mounter/mounter-s3fs_test.go b/pkg/mounter/mounter-s3fs_test.go index b3d49cc1..ad4b08f0 100644 --- a/pkg/mounter/mounter-s3fs_test.go +++ b/pkg/mounter/mounter-s3fs_test.go @@ -84,7 +84,7 @@ func TestS3FSMount_NodeServer_Positive(t *testing.T) { s3fs := &S3fsMounter{ MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseMountFn: func(path, comm string, args []string) error { + FuseMountFn: func(ctx context.Context, path, comm string, args []string) error { return nil }, }), @@ -113,7 +113,7 @@ func TestS3FSMount_WorkerNode_Positive(t *testing.T) { s3fs := &S3fsMounter{ MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseMountFn: func(path, comm string, args []string) error { + FuseMountFn: func(ctx context.Context, path, comm string, args []string) error { return nil }, }), @@ -186,7 +186,7 @@ func TestUnmount_NodeServer(t *testing.T) { s3fs := &S3fsMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return nil }, }), @@ -204,7 +204,7 @@ func TestUnmount_WorkerNode(t *testing.T) { s3fs := &S3fsMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return nil }, }), @@ -224,7 +224,7 @@ func TestUnmount_WorkerNode_Negative(t *testing.T) { s3fs := &S3fsMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return nil }, }), @@ -247,7 +247,7 @@ func TestUnmount_NodeServer_Negative(t *testing.T) { s3fs := &S3fsMounter{ logger: zap.NewNop(), MounterUtils: mounterUtils.NewFakeMounterUtilsImpl(mounterUtils.FakeMounterUtilsFuncStruct{ - FuseUnmountFn: func(path string) error { + FuseUnmountFn: func(ctx context.Context, path string) error { return errors.New("failed to unmount") }, }), diff --git a/pkg/mounter/utils/fake_mounter_utils.go b/pkg/mounter/utils/fake_mounter_utils.go index 72a843cd..eb7267b2 100644 --- a/pkg/mounter/utils/fake_mounter_utils.go +++ b/pkg/mounter/utils/fake_mounter_utils.go @@ -1,8 +1,10 @@ package utils +import "context" + type FakeMounterUtilsFuncStruct struct { - FuseMountFn func(path string, comm string, args []string) error - FuseUnmountFn func(path string) error + FuseMountFn func(ctx context.Context, path string, comm string, args []string) error + FuseUnmountFn func(ctx context.Context, path string) error } type FakeMounterUtilsFuncStructImpl struct { @@ -15,16 +17,16 @@ func NewFakeMounterUtilsImpl(reqFn FakeMounterUtilsFuncStruct) *FakeMounterUtils } } -func (m *FakeMounterUtilsFuncStructImpl) FuseMount(path string, comm string, args []string) error { +func (m *FakeMounterUtilsFuncStructImpl) FuseMount(ctx context.Context, path string, comm string, args []string) error { if m.FuncStruct.FuseMountFn != nil { - return m.FuncStruct.FuseMountFn(path, comm, args) + return m.FuncStruct.FuseMountFn(ctx, path, comm, args) } panic("requested method should not be nil") } -func (m *FakeMounterUtilsFuncStructImpl) FuseUnmount(path string) error { +func (m *FakeMounterUtilsFuncStructImpl) FuseUnmount(ctx context.Context, path string) error { if m.FuncStruct.FuseUnmountFn != nil { - return m.FuncStruct.FuseUnmountFn(path) + return m.FuncStruct.FuseUnmountFn(ctx, path) } panic("requested method should not be nil") } diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index 042de091..5bdbbbc9 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -29,25 +29,41 @@ var ErrTimeoutWaitProcess = errors.New("timeout waiting for process to end") var mounterUtilLogger *zap.Logger func init() { - mounterUtilLogger = logger.NewConsoleLoggerOrNop("mounter-utils") + mounterUtilLogger = logger.NewJSONLoggerOrNop("cos-csi-mounter") + mounterUtilLogger = mounterUtilLogger.With(zap.String("component", "mounter-utils")) +} + +// getRequestIDFromContext extracts request_id from context +func getRequestIDFromContext(ctx context.Context) string { + if ctx == nil { + return "unknown" + } + if reqID, ok := ctx.Value("request_id").(string); ok && reqID != "" { + return reqID + } + return "unknown" } type MounterUtils interface { - FuseUnmount(path string) error - FuseMount(path string, comm string, args []string) error + FuseUnmount(ctx context.Context, path string) error + FuseMount(ctx context.Context, path string, comm string, args []string) error } type MounterOptsUtils struct { } -func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) error { - mounterUtilLogger.Info("FuseMount started") - mounterUtilLogger.Info("FuseMount parameters", +func (su *MounterOptsUtils) FuseMount(ctx context.Context, path string, comm string, args []string) error { + // Extract request_id from context for logging + requestID := getRequestIDFromContext(ctx) + log := mounterUtilLogger.With(zap.String("request_id", requestID)) + + log.Info("FuseMount started") + log.Info("FuseMount parameters", zap.String("path", path), zap.String("command", comm), zap.Strings("args", args)) - ctx, cancel := context.WithCancel(context.Background()) + mountCtx, cancel := context.WithCancel(ctx) var mounted bool defer func() { if !mounted { @@ -55,36 +71,36 @@ func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) e } }() - cmd := commandWithCtx(ctx, comm, args...) + cmd := commandWithCtx(mountCtx, comm, args...) err := cmd.Start() if err != nil { - mounterUtilLogger.Error("FuseMount: command start failed", + log.Error("FuseMount: command start failed", zap.String("mounter", comm), zap.Strings("args", args), zap.Error(err)) return fmt.Errorf("FuseMount: '%s' command start failed: %v", comm, err) } - mounterUtilLogger.Info("FuseMount: command start succeeded", zap.String("mounter", comm)) + log.Info("FuseMount: command start succeeded", zap.String("mounter", comm)) waitCh := make(chan error, 1) mountCh := make(chan error, 1) go func() { - mounterUtilLogger.Info("FuseMount: cmd.Wait() goroutine start", + log.Info("FuseMount: cmd.Wait() goroutine start", zap.String("mounter", comm), zap.String("path", path)) waitCh <- cmd.Wait() - mounterUtilLogger.Info("FuseMount: cmd.Wait() goroutine end", + log.Info("FuseMount: cmd.Wait() goroutine end", zap.String("mounter", comm), zap.String("path", path)) }() go func() { - mounterUtilLogger.Info("FuseMount: waitForMount() goroutine start", + log.Info("FuseMount: waitForMount() goroutine start", zap.String("mounter", comm), zap.String("path", path)) - mountCh <- waitForMount(ctx, path, 2*time.Second, 30*time.Second) // kubelet retries NodePublishVolume after 120 seconds - mounterUtilLogger.Info("FuseMount: waitForMount() goroutine end", + mountCh <- waitForMount(mountCtx, path, 2*time.Second, 30*time.Second) // kubelet retries NodePublishVolume after 120 seconds + log.Info("FuseMount: waitForMount() goroutine end", zap.String("mounter", comm), zap.String("path", path)) }() @@ -92,90 +108,94 @@ func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) e select { case err := <-waitCh: if err != nil { - mounterUtilLogger.Warn("FuseMount: command wait failed", + log.Warn("FuseMount: command wait failed", zap.String("mounter", comm), zap.Strings("args", args), zap.Error(err)) - mounterUtilLogger.Info("FuseMount: checking if path already exists and is a mountpoint", + log.Info("FuseMount: checking if path already exists and is a mountpoint", zap.String("path", path)) if isMount, err1 := isMountpoint(path); err1 == nil && isMount { // check if bucket already got mounted - mounterUtilLogger.Info("Bucket is already mounted", zap.String("mounter", comm)) + log.Info("Bucket is already mounted", zap.String("mounter", comm)) mounted = true return nil } return fmt.Errorf("'%s' mount failed: %v", comm, err) } - mounterUtilLogger.Info("FuseMount: command wait succeeded", zap.String("mounter", comm)) + log.Info("FuseMount: command wait succeeded", zap.String("mounter", comm)) if err := <-mountCh; err != nil { return err } case err := <-mountCh: if err != nil { - mounterUtilLogger.Error("FuseMount: path is not mountpoint, mount failed", + log.Error("FuseMount: path is not mountpoint, mount failed", zap.String("mounter", comm), zap.String("path", path)) return fmt.Errorf("'%s' mount failed: %v", comm, err) } } - mounterUtilLogger.Info("Bucket mounted successfully", zap.String("mounter", comm)) + log.Info("Bucket mounted successfully", zap.String("mounter", comm)) mounted = true return nil } -func (su *MounterOptsUtils) FuseUnmount(path string) error { - mounterUtilLogger.Info("FuseUnmount started", zap.String("path", path)) +func (su *MounterOptsUtils) FuseUnmount(ctx context.Context, path string) error { + // Extract request_id from context for logging + requestID := getRequestIDFromContext(ctx) + log := mounterUtilLogger.With(zap.String("request_id", requestID)) + + log.Info("FuseUnmount started", zap.String("path", path)) // check if mountpoint exists isMount, checkMountErr := isMountpoint(path) if isMount || checkMountErr != nil { - mounterUtilLogger.Info("isMountpoint check", zap.Bool("is_mount", isMount)) + log.Info("isMountpoint check", zap.Bool("is_mount", isMount)) err := unmount(path, 0) if err != nil { - mounterUtilLogger.Warn("Standard unmount failed, trying lazy unmount", + log.Warn("Standard unmount failed, trying lazy unmount", zap.String("path", path), zap.Error(err)) // Try lazy (MNT_DETACH) unmount err = unmount(path, syscall.MNT_DETACH) if err != nil { - mounterUtilLogger.Warn("Lazy unmount failed, trying force unmount", + log.Warn("Lazy unmount failed, trying force unmount", zap.String("path", path), zap.Error(err)) // Try force unmount as last resort err = unmount(path, syscall.MNT_FORCE) if err != nil { - mounterUtilLogger.Error("Force unmount failed", + log.Error("Force unmount failed", zap.String("path", path), zap.Error(err)) return fmt.Errorf("all unmount attempts failed for %s: %v", path, err) } - mounterUtilLogger.Info("Force unmounted successfully", zap.String("path", path)) + log.Info("Force unmounted successfully", zap.String("path", path)) } else { - mounterUtilLogger.Info("Lazy unmounted successfully", zap.String("path", path)) + log.Info("Lazy unmounted successfully", zap.String("path", path)) } } else { - mounterUtilLogger.Info("Unmounted with standard unmount successfully", zap.String("path", path)) + log.Info("Unmounted with standard unmount successfully", zap.String("path", path)) } } // as fuse quits immediately, we will try to wait until the process is done process, err := findFuseMountProcess(path) if err != nil { - mounterUtilLogger.Info("Error getting PID of fuse mount", zap.Error(err)) + log.Info("Error getting PID of fuse mount", zap.Error(err)) return nil } if process == nil { - mounterUtilLogger.Info("Unable to find PID of fuse mount, it must have finished already", + log.Info("Unable to find PID of fuse mount, it must have finished already", zap.String("path", path)) return nil } - mounterUtilLogger.Info("Found fuse pid of mount, checking if it still runs", + log.Info("Found fuse pid of mount, checking if it still runs", zap.Int("pid", process.Pid), zap.String("path", path)) err = waitForProcess(process, 1) if errors.Is(err, ErrTimeoutWaitProcess) { - mounterUtilLogger.Info("Timeout waiting for pid to end, killing process", + log.Info("Timeout waiting for pid to end, killing process", zap.Int("pid", process.Pid)) return process.Kill() } diff --git a/tests/sanity/sanity_test.go b/tests/sanity/sanity_test.go index 1a3c123e..cd8437f9 100644 --- a/tests/sanity/sanity_test.go +++ b/tests/sanity/sanity_test.go @@ -229,11 +229,11 @@ func (v providerIDGenerator) GenerateUniqueValidVolumeID() string { type FakeNewMounterOptsUtils struct { } -func (su *FakeNewMounterOptsUtils) FuseUnmount(path string) error { +func (su *FakeNewMounterOptsUtils) FuseUnmount(ctx context.Context, path string) error { return nil } -func (m *FakeNewMounterOptsUtils) FuseMount(path string, comm string, args []string) error { +func (m *FakeNewMounterOptsUtils) FuseMount(ctx context.Context, path string, comm string, args []string) error { return nil } From 23e5631c2530d3d665694a19a0efb9bedc04055d Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 16 Jun 2026 18:04:09 +0530 Subject: [PATCH 50/64] linter fix --- cos-csi-mounter/server/server.go | 11 +++++++++-- pkg/mounter/utils/mounter_utils.go | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index bca8f15d..ef763431 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -24,6 +24,13 @@ import ( "go.uber.org/zap/zapcore" ) +// contextKey is a custom type for context keys to avoid collisions +type contextKey string + +const ( + requestIDKey contextKey = "request_id" +) + var ( logger *zap.Logger MakeDir = os.MkdirAll @@ -218,7 +225,7 @@ func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) zap.String("mounter", request.Mounter)) // Create context with request_id for end-to-end tracing - ctx := context.WithValue(c.Request.Context(), "request_id", reqID) + ctx := context.WithValue(c.Request.Context(), requestIDKey, reqID) err = mounter.FuseMount(ctx, request.Path, request.Mounter, args) if err != nil { log.Error("Mount failed", zap.Error(err)) @@ -257,7 +264,7 @@ func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { log.Info("Unmounting bucket", zap.String("path", request.Path)) // Create context with request_id for end-to-end tracing - ctx := context.WithValue(c.Request.Context(), "request_id", reqID) + ctx := context.WithValue(c.Request.Context(), requestIDKey, reqID) err := mounter.FuseUnmount(ctx, request.Path) if err != nil { log.Error("Unmount failed", zap.Error(err)) diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index 5bdbbbc9..53f4ae84 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -20,6 +20,13 @@ import ( k8sMountUtils "k8s.io/mount-utils" ) +// contextKey is a custom type for context keys to avoid collisions +type contextKey string + +const ( + requestIDKey contextKey = "request_id" +) + var unmount = syscall.Unmount var commandWithCtx = exec.CommandContext @@ -38,7 +45,7 @@ func getRequestIDFromContext(ctx context.Context) string { if ctx == nil { return "unknown" } - if reqID, ok := ctx.Value("request_id").(string); ok && reqID != "" { + if reqID, ok := ctx.Value(requestIDKey).(string); ok && reqID != "" { return reqID } return "unknown" From 0f737248e5dc377513822158c0837653715570f8 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 16 Jun 2026 20:05:53 +0530 Subject: [PATCH 51/64] minor chages format --- pkg/mounter/mounter-rclone.go | 8 +++++--- pkg/mounter/mounter-s3fs.go | 8 +++++--- pkg/utils/driver_utils.go | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pkg/mounter/mounter-rclone.go b/pkg/mounter/mounter-rclone.go index 81c5b68c..ec5dd1d1 100644 --- a/pkg/mounter/mounter-rclone.go +++ b/pkg/mounter/mounter-rclone.go @@ -65,7 +65,8 @@ var ( ) func init() { - rcloneLogger = logger.NewConsoleLoggerOrNop("rclone-mounter") + rcloneLogger = logger.NewJSONLoggerOrNop("rclone-mounter") + rcloneLogger = rcloneLogger.With(zap.String("component", "rclone-mounter")) } func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils) Mounter { @@ -135,8 +136,9 @@ func NewRcloneMounter(secretMap map[string]string, mountOptions []string, mounte mounter.MounterUtils = mounterUtils - // Initialize logger - use console logger or fallback to nop - mounter.logger = logger.NewConsoleLoggerOrNop("rclone-mounter") + // Initialize logger - use JSON logger or fallback to nop + mounter.logger = logger.NewJSONLoggerOrNop("rclone-mounter") + mounter.logger = mounter.logger.With(zap.String("component", "rclone-mounter")) return mounter } diff --git a/pkg/mounter/mounter-s3fs.go b/pkg/mounter/mounter-s3fs.go index 669bde93..dc842e81 100644 --- a/pkg/mounter/mounter-s3fs.go +++ b/pkg/mounter/mounter-s3fs.go @@ -60,7 +60,8 @@ var ( ) func init() { - s3fsLogger = logger.NewConsoleLoggerOrNop("s3fs-mounter") + s3fsLogger = logger.NewJSONLoggerOrNop("s3fs-mounter") + s3fsLogger = s3fsLogger.With(zap.String("component", "s3fs-mounter")) } func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterUtils utils.MounterUtils, defaultParams map[string]string) Mounter { @@ -116,8 +117,9 @@ func NewS3fsMounter(secretMap map[string]string, mountOptions []string, mounterU mounter.MounterUtils = mounterUtils - // Initialize logger - use console logger or fallback to nop - mounter.logger = logger.NewConsoleLoggerOrNop("s3fs-mounter") + // Initialize logger - use JSON logger or fallback to nop + mounter.logger = logger.NewJSONLoggerOrNop("s3fs-mounter") + mounter.logger = mounter.logger.With(zap.String("component", "s3fs-mounter")) return mounter } diff --git a/pkg/utils/driver_utils.go b/pkg/utils/driver_utils.go index df37894e..16272232 100644 --- a/pkg/utils/driver_utils.go +++ b/pkg/utils/driver_utils.go @@ -26,7 +26,8 @@ import ( var utilLogger *zap.Logger func init() { - utilLogger = logger.NewConsoleLoggerOrNop("driver-utils") + utilLogger = logger.NewJSONLoggerOrNop("ibm-object-csi-driver") + utilLogger = utilLogger.With(zap.String("component", "driver-utils")) } type StatsUtils interface { From c0f2edd869e9da70b550d5d0b30d3d72225ee5f0 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 16 Jun 2026 21:04:29 +0530 Subject: [PATCH 52/64] format related changes --- pkg/driver/s3-driver_test.go | 9 +++++++-- pkg/mounter/utils/mounter_utils_stub.go | 13 ++++++++----- tests/sanity/sanity_test.go | 9 +++++++-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pkg/driver/s3-driver_test.go b/pkg/driver/s3-driver_test.go index 46ad9cea..61b651b9 100644 --- a/pkg/driver/s3-driver_test.go +++ b/pkg/driver/s3-driver_test.go @@ -36,8 +36,13 @@ const defaultMode = "controller" // GetTestLogger ... func GetTestLogger(t *testing.T) (logger *zap.Logger, teardown func()) { - config := zap.NewDevelopmentConfig() - config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + config := zap.NewProductionConfig() + config.EncoderConfig.TimeKey = "timestamp" + config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + config.EncoderConfig.EncodeLevel = zapcore.LowercaseLevelEncoder + config.EncoderConfig.MessageKey = "msg" + config.EncoderConfig.CallerKey = "caller" + config.EncoderConfig.LevelKey = "level" buf := &bytes.Buffer{} logger, _ = config.Build() diff --git a/pkg/mounter/utils/mounter_utils_stub.go b/pkg/mounter/utils/mounter_utils_stub.go index 71a89dc4..5c88eb3e 100644 --- a/pkg/mounter/utils/mounter_utils_stub.go +++ b/pkg/mounter/utils/mounter_utils_stub.go @@ -3,19 +3,22 @@ package utils -import "fmt" +import ( + "context" + "fmt" +) type MounterUtils interface { - FuseUnmount(path string) error - FuseMount(path string, comm string, args []string) error + FuseUnmount(ctx context.Context, path string) error + FuseMount(ctx context.Context, path string, comm string, args []string) error } type MounterOptsUtils struct{} -func (su *MounterOptsUtils) FuseMount(path string, comm string, args []string) error { +func (su *MounterOptsUtils) FuseMount(ctx context.Context, path string, comm string, args []string) error { return fmt.Errorf("FuseMount not supported on this platform") } -func (su *MounterOptsUtils) FuseUnmount(path string) error { +func (su *MounterOptsUtils) FuseUnmount(ctx context.Context, path string) error { return fmt.Errorf("FuseUnmount not supported on this platform") } diff --git a/tests/sanity/sanity_test.go b/tests/sanity/sanity_test.go index cd8437f9..cd633395 100644 --- a/tests/sanity/sanity_test.go +++ b/tests/sanity/sanity_test.go @@ -29,6 +29,7 @@ import ( "github.com/google/uuid" "github.com/kubernetes-csi/csi-test/v5/pkg/sanity" "go.uber.org/zap" + "go.uber.org/zap/zapcore" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" @@ -182,8 +183,12 @@ type FakeS3fsMounterFactory struct { } func FakeNewS3fsMounterFactory() *FakeS3fsMounterFactory { - // Create a no-op logger for tests - logger, _ := zap.NewDevelopment() + // Create a JSON logger for tests + config := zap.NewProductionConfig() + config.EncoderConfig.TimeKey = "timestamp" + config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + config.EncoderConfig.EncodeLevel = zapcore.LowercaseLevelEncoder + logger, _ := config.Build() return &FakeS3fsMounterFactory{logger: logger} } From 843aec6fb4309205e948289528047d7f3054514f Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 16 Jun 2026 21:17:42 +0530 Subject: [PATCH 53/64] publish v0.12.37 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2284b364..977061ee 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: v0.12.36 + APP_VERSION: v0.12.37 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: v0.12.36 - name: v0.12.36 + tag_name: v0.12.37 + name: v0.12.37 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 6b371e8f..3f7f9aaa 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := v0.12.36 +APP_VERSION := v0.12.37 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From d8651f7fe19abb9ae95175b8bf83bcb7f558b7b7 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Tue, 16 Jun 2026 21:29:06 +0530 Subject: [PATCH 54/64] publish 0.12.37 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 977061ee..872b9b62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: v0.12.37 + APP_VERSION: 0.12.37 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: v0.12.37 - name: v0.12.37 + tag_name: 0.12.37 + name: 0.12.37 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 3f7f9aaa..11934e4a 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := v0.12.37 +APP_VERSION := 0.12.37 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 243a305f481674950c040524bd45fee938009710 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 17 Jun 2026 16:47:41 +0530 Subject: [PATCH 55/64] mounter unknown requestID fix --- pkg/mounter/utils/mounter_utils.go | 48 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index 53f4ae84..336cca59 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -106,7 +106,7 @@ func (su *MounterOptsUtils) FuseMount(ctx context.Context, path string, comm str log.Info("FuseMount: waitForMount() goroutine start", zap.String("mounter", comm), zap.String("path", path)) - mountCh <- waitForMount(mountCtx, path, 2*time.Second, 30*time.Second) // kubelet retries NodePublishVolume after 120 seconds + mountCh <- waitForMount(mountCtx, log, path, 2*time.Second, 30*time.Second) // kubelet retries NodePublishVolume after 120 seconds log.Info("FuseMount: waitForMount() goroutine end", zap.String("mounter", comm), zap.String("path", path)) @@ -121,7 +121,7 @@ func (su *MounterOptsUtils) FuseMount(ctx context.Context, path string, comm str zap.Error(err)) log.Info("FuseMount: checking if path already exists and is a mountpoint", zap.String("path", path)) - if isMount, err1 := isMountpoint(path); err1 == nil && isMount { // check if bucket already got mounted + if isMount, err1 := isMountpoint(log, path); err1 == nil && isMount { // check if bucket already got mounted log.Info("Bucket is already mounted", zap.String("mounter", comm)) mounted = true return nil @@ -154,7 +154,7 @@ func (su *MounterOptsUtils) FuseUnmount(ctx context.Context, path string) error log.Info("FuseUnmount started", zap.String("path", path)) // check if mountpoint exists - isMount, checkMountErr := isMountpoint(path) + isMount, checkMountErr := isMountpoint(log, path) if isMount || checkMountErr != nil { log.Info("isMountpoint check", zap.Bool("is_mount", isMount)) err := unmount(path, 0) @@ -186,7 +186,7 @@ func (su *MounterOptsUtils) FuseUnmount(ctx context.Context, path string) error } // as fuse quits immediately, we will try to wait until the process is done - process, err := findFuseMountProcess(path) + process, err := findFuseMountProcess(log, path) if err != nil { log.Info("Error getting PID of fuse mount", zap.Error(err)) return nil @@ -200,7 +200,7 @@ func (su *MounterOptsUtils) FuseUnmount(ctx context.Context, path string) error zap.Int("pid", process.Pid), zap.String("path", path)) - err = waitForProcess(process, 1) + err = waitForProcess(log, process, 1) if errors.Is(err, ErrTimeoutWaitProcess) { log.Info("Timeout waiting for pid to end, killing process", zap.Int("pid", process.Pid)) @@ -210,12 +210,12 @@ func (su *MounterOptsUtils) FuseUnmount(ctx context.Context, path string) error return err } -func isMountpoint(pathname string) (bool, error) { - mounterUtilLogger.Info("Checking if path is mountpoint", zap.String("pathname", pathname)) +func isMountpoint(log *zap.Logger, pathname string) (bool, error) { + log.Info("Checking if path is mountpoint", zap.String("pathname", pathname)) out, err := exec.Command("mountpoint", pathname).CombinedOutput() outStr := strings.ToLower(strings.TrimSpace(string(out))) - mounterUtilLogger.Info("Mountpoint status", + log.Info("Mountpoint status", zap.String("path", pathname), zap.Error(err), zap.String("output", string(out))) @@ -224,24 +224,24 @@ func isMountpoint(pathname string) (bool, error) { return true, nil } if strings.HasSuffix(outStr, "is not a mountpoint") { - mounterUtilLogger.Info("Path is NOT a mountpoint", zap.String("pathname", pathname)) + log.Info("Path is NOT a mountpoint", zap.String("pathname", pathname)) return false, nil } - mounterUtilLogger.Error("Failed to check mountpoint for path", + log.Error("Failed to check mountpoint for path", zap.String("path", pathname), zap.Error(err), zap.String("output", string(out))) return false, fmt.Errorf("failed to check mountpoint for path '%s', error: %v, output: %s", pathname, err, string(out)) } if strings.HasSuffix(outStr, "is a mountpoint") { - mounterUtilLogger.Info("Path is a mountpoint", zap.String("pathname", pathname)) + log.Info("Path is a mountpoint", zap.String("pathname", pathname)) return true, nil } return false, nil } -func waitForMount(ctx context.Context, path string, initialDelay, timeout time.Duration) error { +func waitForMount(ctx context.Context, log *zap.Logger, path string, initialDelay, timeout time.Duration) error { if initialDelay > 0 { time.Sleep(initialDelay) } @@ -251,16 +251,16 @@ func waitForMount(ctx context.Context, path string, initialDelay, timeout time.D select { case <-ctx.Done(): err := ctx.Err() - mounterUtilLogger.Info("waitForMount: context is done", zap.Error(err)) + log.Info("waitForMount: context is done", zap.Error(err)) return err default: isMount, err := k8sMountUtils.New("").IsMountPoint(path) if err == nil && isMount { - mounterUtilLogger.Info("Path is a mountpoint", zap.String("pathname", path)) + log.Info("Path is a mountpoint", zap.String("pathname", path)) return nil } - mounterUtilLogger.Info("Mountpoint check in progress", + log.Info("Mountpoint check in progress", zap.Int("attempt", attempt), zap.String("path", path), zap.Bool("is_mount", isMount), @@ -276,7 +276,7 @@ func waitForMount(ctx context.Context, path string, initialDelay, timeout time.D } } -func findFuseMountProcess(path string) (*os.Process, error) { +func findFuseMountProcess(log *zap.Logger, path string) (*os.Process, error) { processes, err := ps.Processes() if err != nil { return nil, err @@ -284,13 +284,13 @@ func findFuseMountProcess(path string) (*os.Process, error) { for _, p := range processes { cmdLine, err := getCmdLine(p.Pid()) if err != nil { - mounterUtilLogger.Error("Unable to get cmdline of PID", + log.Error("Unable to get cmdline of PID", zap.Int("pid", p.Pid()), zap.Error(err)) continue } if strings.Contains(cmdLine, path) { - mounterUtilLogger.Info("Found matching pid on path", + log.Info("Found matching pid on path", zap.Int("pid", p.Pid()), zap.String("path", path)) return os.FindProcess(p.Pid()) @@ -308,14 +308,14 @@ func getCmdLine(pid int) (string, error) { return string(cmdLine), nil } -func waitForProcess(p *os.Process, backoff int) error { +func waitForProcess(log *zap.Logger, p *os.Process, backoff int) error { // totally it waits 60 seconds before force killing the process if backoff == 120 { return ErrTimeoutWaitProcess } cmdLine, err := getCmdLine(p.Pid) if err != nil { - mounterUtilLogger.Warn("Error checking cmdline of PID, assuming it is dead", + log.Warn("Error checking cmdline of PID, assuming it is dead", zap.Int("pid", p.Pid), zap.Error(err)) return nil @@ -324,17 +324,17 @@ func waitForProcess(p *os.Process, backoff int) error { // ignore defunct processes // TODO: debug why this happens in the first place // seems to only happen on k8s, not on local docker - mounterUtilLogger.Warn("Fuse process seems dead, returning") + log.Warn("Fuse process seems dead, returning") return nil } if err := p.Signal(syscall.Signal(0)); err != nil { - mounterUtilLogger.Warn("Fuse process does not seem active or we are unprivileged", + log.Warn("Fuse process does not seem active or we are unprivileged", zap.Error(err)) return nil } - mounterUtilLogger.Info("Fuse process still active, waiting", + log.Info("Fuse process still active, waiting", zap.Int("pid", p.Pid), zap.Int("backoff", backoff)) time.Sleep(time.Duration(500) * time.Millisecond) - return waitForProcess(p, backoff+1) + return waitForProcess(log, p, backoff+1) } From edad15bf3dbd71fcd8a591d200e9923136b8f5a1 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 17 Jun 2026 16:54:59 +0530 Subject: [PATCH 56/64] publish 0.12.38 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 872b9b62..4457c965 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.37 + APP_VERSION: 0.12.38 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.37 - name: 0.12.37 + tag_name: 0.12.38 + name: 0.12.38 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 11934e4a..339cc2a8 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.37 +APP_VERSION := 0.12.38 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 253743098afb625783ff8dcf0828b9a01735724c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 17 Jun 2026 21:16:57 +0530 Subject: [PATCH 57/64] unkonown requestid fix --- cos-csi-mounter/server/server.go | 11 ++--------- pkg/mounter/utils/mounter_utils.go | 10 +++------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/cos-csi-mounter/server/server.go b/cos-csi-mounter/server/server.go index ef763431..bd0a97e3 100644 --- a/cos-csi-mounter/server/server.go +++ b/cos-csi-mounter/server/server.go @@ -24,13 +24,6 @@ import ( "go.uber.org/zap/zapcore" ) -// contextKey is a custom type for context keys to avoid collisions -type contextKey string - -const ( - requestIDKey contextKey = "request_id" -) - var ( logger *zap.Logger MakeDir = os.MkdirAll @@ -225,7 +218,7 @@ func handleCosMount(mounter mounterUtils.MounterUtils, parser MounterArgsParser) zap.String("mounter", request.Mounter)) // Create context with request_id for end-to-end tracing - ctx := context.WithValue(c.Request.Context(), requestIDKey, reqID) + ctx := context.WithValue(c.Request.Context(), mounterUtils.RequestIDKey, reqID) err = mounter.FuseMount(ctx, request.Path, request.Mounter, args) if err != nil { log.Error("Mount failed", zap.Error(err)) @@ -264,7 +257,7 @@ func handleCosUnmount(mounter mounterUtils.MounterUtils) gin.HandlerFunc { log.Info("Unmounting bucket", zap.String("path", request.Path)) // Create context with request_id for end-to-end tracing - ctx := context.WithValue(c.Request.Context(), requestIDKey, reqID) + ctx := context.WithValue(c.Request.Context(), mounterUtils.RequestIDKey, reqID) err := mounter.FuseUnmount(ctx, request.Path) if err != nil { log.Error("Unmount failed", zap.Error(err)) diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index 336cca59..eb14b73f 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -20,12 +20,8 @@ import ( k8sMountUtils "k8s.io/mount-utils" ) -// contextKey is a custom type for context keys to avoid collisions -type contextKey string - -const ( - requestIDKey contextKey = "request_id" -) +// RequestIDKey is the context key for request ID (exported for use by other packages) +const RequestIDKey = "ibm-cos-csi-request-id" var unmount = syscall.Unmount var commandWithCtx = exec.CommandContext @@ -45,7 +41,7 @@ func getRequestIDFromContext(ctx context.Context) string { if ctx == nil { return "unknown" } - if reqID, ok := ctx.Value(requestIDKey).(string); ok && reqID != "" { + if reqID, ok := ctx.Value(RequestIDKey).(string); ok && reqID != "" { return reqID } return "unknown" From 9224ca88a1a4c59cecdbc36752488c8534c58e4f Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 17 Jun 2026 21:21:10 +0530 Subject: [PATCH 58/64] publish 0.12.39 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4457c965..ccb839f5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.38 + APP_VERSION: 0.12.39 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.38 - name: 0.12.38 + tag_name: 0.12.39 + name: 0.12.39 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 339cc2a8..6955353e 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.38 +APP_VERSION := 0.12.39 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From 908125479bfe4ce185483d5d7990c04ea260d25b Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 17 Jun 2026 21:33:05 +0530 Subject: [PATCH 59/64] publish 0.12.39 --- pkg/mounter/utils/mounter_utils.go | 5 ++++- pkg/requestid/requestid.go | 9 ++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/mounter/utils/mounter_utils.go b/pkg/mounter/utils/mounter_utils.go index eb14b73f..042dbe13 100644 --- a/pkg/mounter/utils/mounter_utils.go +++ b/pkg/mounter/utils/mounter_utils.go @@ -20,8 +20,11 @@ import ( k8sMountUtils "k8s.io/mount-utils" ) +// ContextKey is a custom type for context keys to avoid collisions +type ContextKey string + // RequestIDKey is the context key for request ID (exported for use by other packages) -const RequestIDKey = "ibm-cos-csi-request-id" +const RequestIDKey ContextKey = "ibm-cos-csi-request-id" var unmount = syscall.Unmount var commandWithCtx = exec.CommandContext diff --git a/pkg/requestid/requestid.go b/pkg/requestid/requestid.go index 3a766829..e5fe8876 100644 --- a/pkg/requestid/requestid.go +++ b/pkg/requestid/requestid.go @@ -18,11 +18,12 @@ import ( "github.com/google/uuid" ) -type contextKey string +// ContextKey is a custom type for context keys to avoid collisions +type ContextKey string const ( // RequestIDKey is the context key for storing request IDs - RequestIDKey contextKey = "request-id" + RequestIDKey ContextKey = "request-id" ) // Generate creates a new UUID v4 request ID @@ -56,7 +57,7 @@ func GetOrGenerate(ctx context.Context) (context.Context, string) { if ctx == nil { ctx = context.Background() } - + requestID := FromContext(ctx) if requestID == "" { requestID = Generate() @@ -74,5 +75,3 @@ func MustGet(ctx context.Context) string { } return requestID } - - From de9598158bf065fb302274cab50e0a864296219c Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 25 Jun 2026 01:13:32 +0530 Subject: [PATCH 60/64] correct inconsistent logging pattern,request id in msg field --- pkg/mounter/mounter.go | 17 ++++----- pkg/s3client/s3client.go | 76 ++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go index af0aa9b6..297987f2 100644 --- a/pkg/mounter/mounter.go +++ b/pkg/mounter/mounter.go @@ -136,17 +136,18 @@ func writePass(pwFileName string, pwFileContent string) error { func createCOSCSIMounterRequest(ctx context.Context, payload string, url string, log *zap.Logger) error { reqID := requestid.FromContext(ctx) + logWithReqID := log.With(zap.String("request_id", reqID)) // Get socket path socketPath := os.Getenv(constants.COSCSIMounterSocketPathEnv) if socketPath == "" { socketPath = constants.COSCSIMounterSocketPath } - log.Info(fmt.Sprintf("[%s] COS CSI Mounter Socket Path", reqID), zap.String("socket_path", socketPath)) + logWithReqID.Info("COS CSI Mounter Socket Path", zap.String("socket_path", socketPath)) err := isGRPCServerAvailable(socketPath) if err != nil { - log.Error(fmt.Sprintf("[%s] COS CSI Mounter service not available", reqID), zap.Error(err)) + logWithReqID.Error("COS CSI Mounter service not available", zap.Error(err)) return err } @@ -166,33 +167,33 @@ func createCOSCSIMounterRequest(ctx context.Context, payload string, url string, // Create POST request req, err := http.NewRequest("POST", url, strings.NewReader(payload)) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to create HTTP request", reqID), zap.Error(err)) + logWithReqID.Error("Failed to create HTTP request", zap.Error(err)) return err } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Request-ID", reqID) // Add request ID to HTTP header - log.Info(fmt.Sprintf("[%s] Sending request to cos-csi-mounter", reqID), zap.String("url", url)) + logWithReqID.Info("Sending request to cos-csi-mounter", zap.String("url", url)) response, err := client.Do(req) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to send request to cos-csi-mounter", reqID), zap.Error(err)) + logWithReqID.Error("Failed to send request to cos-csi-mounter", zap.Error(err)) return err } defer func() { if err := response.Body.Close(); err != nil { - log.Error(fmt.Sprintf("[%s] Failed to close response body", reqID), zap.Error(err)) + logWithReqID.Error("Failed to close response body", zap.Error(err)) } }() body, err := io.ReadAll(response.Body) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to read response body", reqID), zap.Error(err)) + logWithReqID.Error("Failed to read response body", zap.Error(err)) return err } responseBody := string(body) - log.Info(fmt.Sprintf("[%s] Response from cos-csi-mounter", reqID), + logWithReqID.Info("Response from cos-csi-mounter", zap.String("response_body", responseBody), zap.Int("status_code", response.StatusCode)) diff --git a/pkg/s3client/s3client.go b/pkg/s3client/s3client.go index c5b1d821..5040df17 100644 --- a/pkg/s3client/s3client.go +++ b/pkg/s3client/s3client.go @@ -121,14 +121,14 @@ func (s *COSSession) CheckBucketAccess(ctx context.Context, bucket string) error reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] CheckBucketAccess started", reqID), zap.String("bucket", bucket)) + log.Info("CheckBucketAccess started", zap.String("bucket", bucket)) _, err := s.svc.HeadBucket(&s3.HeadBucketInput{ Bucket: aws.String(bucket), }) if err != nil { - log.Error(fmt.Sprintf("[%s] CheckBucketAccess failed", reqID), zap.String("bucket", bucket), zap.Error(err)) + log.Error("CheckBucketAccess failed", zap.String("bucket", bucket), zap.Error(err)) } else { - log.Info(fmt.Sprintf("[%s] CheckBucketAccess completed", reqID), zap.String("bucket", bucket)) + log.Info("CheckBucketAccess completed", zap.String("bucket", bucket)) } return err } @@ -137,7 +137,7 @@ func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] CheckObjectPathExistence started", reqID), + log.Info("CheckObjectPathExistence started", zap.String("bucket", bucket), zap.String("objectpath", objectpath)) objectpath = strings.TrimPrefix(objectpath, "/") @@ -151,8 +151,8 @@ func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string Prefix: aws.String(objectpath), }) if err != nil { - log.Error(fmt.Sprintf("[%s] Cannot list bucket", reqID), zap.String("bucket", bucket), zap.Error(err)) - return false, fmt.Errorf("[%s] cannot list bucket '%s': %v", reqID, bucket, err) + log.Error("Cannot list bucket", zap.String("bucket", bucket), zap.Error(err)) + return false, fmt.Errorf("cannot list bucket '%s': %v", bucket, err) } exists := false @@ -163,7 +163,7 @@ func (s *COSSession) CheckObjectPathExistence(ctx context.Context, bucket string } } - log.Info(fmt.Sprintf("[%s] CheckObjectPathExistence completed", reqID), + log.Info("CheckObjectPathExistence completed", zap.String("bucket", bucket), zap.String("objectpath", objectpath), zap.Bool("exists", exists)) return exists, nil } @@ -172,19 +172,19 @@ func (s *COSSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn stri reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] CreateBucket started", reqID), + log.Info("CreateBucket started", zap.String("bucket", bucket), zap.Bool("encryption_enabled", kpRootKeyCrn != "")) if kpRootKeyCrn != "" { - log.Debug(fmt.Sprintf("[%s] Creating bucket with KP encryption", reqID), zap.String("bucket", bucket)) + log.Debug("Creating bucket with KP encryption", zap.String("bucket", bucket)) _, err = s.svc.CreateBucket(&s3.CreateBucketInput{ Bucket: aws.String(bucket), IBMSSEKPCustomerRootKeyCrn: aws.String(kpRootKeyCrn), IBMSSEKPEncryptionAlgorithm: aws.String(constants.KPEncryptionAlgorithm), }) } else { - log.Debug(fmt.Sprintf("[%s] Creating bucket without encryption", reqID), zap.String("bucket", bucket)) + log.Debug("Creating bucket without encryption", zap.String("bucket", bucket)) _, err = s.svc.CreateBucket(&s3.CreateBucketInput{ Bucket: aws.String(bucket), }) @@ -192,14 +192,14 @@ func (s *COSSession) CreateBucket(ctx context.Context, bucket, kpRootKeyCrn stri if err != nil { if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "BucketAlreadyOwnedByYou" { - log.Warn(fmt.Sprintf("[%s] Bucket already exists", reqID), zap.String("bucket", bucket)) - return fmt.Sprintf("[%s] bucket '%s' already exists", reqID, bucket), nil + log.Warn("Bucket already exists", zap.String("bucket", bucket)) + return fmt.Sprintf("bucket '%s' already exists", bucket), nil } - log.Error(fmt.Sprintf("[%s] CreateBucket failed", reqID), zap.String("bucket", bucket), zap.Error(err)) + log.Error("CreateBucket failed", zap.String("bucket", bucket), zap.Error(err)) return "", err } - log.Info(fmt.Sprintf("[%s] CreateBucket completed successfully", reqID), zap.String("bucket", bucket)) + log.Info("CreateBucket completed successfully", zap.String("bucket", bucket)) return "", nil } @@ -207,7 +207,7 @@ func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] DeleteBucket started", reqID), zap.String("bucket", bucket)) + log.Info("DeleteBucket started", zap.String("bucket", bucket)) resp, err := s.svc.ListObjects(&s3.ListObjectsInput{ Bucket: aws.String(bucket), @@ -215,15 +215,15 @@ func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { if err != nil { if aerr, ok := err.(awserr.Error); ok && aerr.Code() == "NoSuchBucket" { - log.Warn(fmt.Sprintf("[%s] Bucket already deleted", reqID), zap.String("bucket", bucket)) + log.Warn("Bucket already deleted", zap.String("bucket", bucket)) return nil } - log.Error(fmt.Sprintf("[%s] Cannot list bucket", reqID), zap.String("bucket", bucket), zap.Error(err)) - return fmt.Errorf("[%s] cannot list bucket '%s': %v", reqID, bucket, err) + log.Error("Cannot list bucket", zap.String("bucket", bucket), zap.Error(err)) + return fmt.Errorf("cannot list bucket '%s': %v", bucket, err) } objectCount := len(resp.Contents) - log.Info(fmt.Sprintf("[%s] Deleting objects from bucket", reqID), + log.Info("Deleting objects from bucket", zap.String("bucket", bucket), zap.Int("object_count", objectCount)) for _, key := range resp.Contents { @@ -233,21 +233,21 @@ func (s *COSSession) DeleteBucket(ctx context.Context, bucket string) error { }) if err != nil { - log.Error(fmt.Sprintf("[%s] Cannot delete object", reqID), + log.Error("Cannot delete object", zap.String("bucket", bucket), zap.String("key", *key.Key), zap.Error(err)) - return fmt.Errorf("[%s] cannot delete object %s/%s: %v", reqID, bucket, *key.Key, err) + return fmt.Errorf("cannot delete object %s/%s: %v", bucket, *key.Key, err) } } - log.Info(fmt.Sprintf("[%s] Deleting bucket", reqID), zap.String("bucket", bucket)) + log.Info("Deleting bucket", zap.String("bucket", bucket)) _, err = s.svc.DeleteBucket(&s3.DeleteBucketInput{ Bucket: aws.String(bucket), }) if err != nil { - log.Error(fmt.Sprintf("[%s] DeleteBucket failed", reqID), zap.String("bucket", bucket), zap.Error(err)) + log.Error("DeleteBucket failed", zap.String("bucket", bucket), zap.Error(err)) } else { - log.Info(fmt.Sprintf("[%s] DeleteBucket completed successfully", reqID), zap.String("bucket", bucket)) + log.Info("DeleteBucket completed successfully", zap.String("bucket", bucket)) } return err } @@ -261,7 +261,7 @@ func (s *COSSession) SetBucketVersioning(ctx context.Context, bucket string, ena status = s3.BucketVersioningStatusEnabled } - log.Info(fmt.Sprintf("[%s] SetBucketVersioning started", reqID), + log.Info("SetBucketVersioning started", zap.String("bucket", bucket), zap.Bool("enable", enable)) _, err := s.svc.PutBucketVersioning(&s3.PutBucketVersioningInput{ @@ -271,12 +271,12 @@ func (s *COSSession) SetBucketVersioning(ctx context.Context, bucket string, ena }, }) if err != nil { - log.Error(fmt.Sprintf("[%s] SetBucketVersioning failed", reqID), + log.Error("SetBucketVersioning failed", zap.String("bucket", bucket), zap.Bool("enable", enable), zap.Error(err)) - return fmt.Errorf("[%s] failed to set versioning to %v for bucket '%s': %v", reqID, enable, bucket, err) + return fmt.Errorf("failed to set versioning to %v for bucket '%s': %v", enable, bucket, err) } - log.Info(fmt.Sprintf("[%s] SetBucketVersioning completed successfully", reqID), + log.Info("SetBucketVersioning completed successfully", zap.String("bucket", bucket), zap.Bool("enable", enable)) return nil } @@ -314,16 +314,16 @@ func (s *COSSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, reqID := requestid.FromContext(ctx) log := s.logger.With(zap.String("request_id", reqID)) - log.Info(fmt.Sprintf("[%s] UpdateQuotaLimit started", reqID), + log.Info("UpdateQuotaLimit started", zap.String("bucket", bucketName), zap.Int64("quota", quota)) var configEndpoint string if strings.Contains(strings.ToLower(cosEndpoint), "private") { configEndpoint = constants.ResourceConfigEPPrivate - log.Debug(fmt.Sprintf("[%s] Using private resource config endpoint", reqID)) + log.Debug("Using private resource config endpoint") } else { configEndpoint = constants.ResourceConfigEPDirect - log.Debug(fmt.Sprintf("[%s] Using direct resource config endpoint", reqID)) + log.Debug("Using direct resource config endpoint") } iamTokenURL := iamEndpoint + "/identity/token" @@ -333,14 +333,14 @@ func (s *COSSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, URL: iamTokenURL, } - log.Debug(fmt.Sprintf("[%s] Creating resource configuration service", reqID)) + log.Debug("Creating resource configuration service") service, err := s.rcClientFactory.NewResourceConfigurationV1(&rc.ResourceConfigurationV1Options{ Authenticator: authenticator, URL: configEndpoint, }) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to create resource configuration service", reqID), zap.Error(err)) - return fmt.Errorf("[%s] failed to create resource configuration service: %w", reqID, err) + log.Error("Failed to create resource configuration service", zap.Error(err)) + return fmt.Errorf("failed to create resource configuration service: %w", err) } bucketPatch := make(map[string]interface{}) @@ -351,16 +351,16 @@ func (s *COSSession) UpdateQuotaLimit(ctx context.Context, quota int64, apiKey, BucketPatch: bucketPatch, } - log.Info(fmt.Sprintf("[%s] Updating bucket quota", reqID), + log.Info("Updating bucket quota", zap.String("bucket", bucketName), zap.Int64("quota", quota)) _, err = service.UpdateBucketConfig(options) if err != nil { - log.Error(fmt.Sprintf("[%s] Failed to update quota", reqID), + log.Error("Failed to update quota", zap.String("bucket", bucketName), zap.Int64("quota", quota), zap.Error(err)) - return fmt.Errorf("[%s] failed to update quota for bucket %s to %d bytes: %w", reqID, bucketName, quota, err) + return fmt.Errorf("failed to update quota for bucket %s to %d bytes: %w", bucketName, quota, err) } - log.Info(fmt.Sprintf("[%s] UpdateQuotaLimit completed successfully", reqID), + log.Info("UpdateQuotaLimit completed successfully", zap.String("bucket", bucketName), zap.Int64("quota", quota)) return nil } From 8b38d0c4c90339c0c7e02e912f4df822a0d09952 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 25 Jun 2026 01:22:55 +0530 Subject: [PATCH 61/64] fix: update test to match corrected error message format without request ID prefix --- pkg/s3client/s3client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/s3client/s3client_test.go b/pkg/s3client/s3client_test.go index 5fd64dbf..212de048 100644 --- a/pkg/s3client/s3client_test.go +++ b/pkg/s3client/s3client_test.go @@ -207,7 +207,7 @@ func Test_SetBucketVersioning_Error(t *testing.T) { sess := getSession(&fakeS3API{ErrPutBucketVersioning: errFoo}) err := sess.SetBucketVersioning(context.Background(), testBucket, true) if assert.Error(t, err) { - assert.EqualError(t, err, "[] failed to set versioning to true for bucket 'test-bucket': foo") + assert.EqualError(t, err, "failed to set versioning to true for bucket 'test-bucket': foo") } } From ff932c7918dc66fa283385b429c545f7beac69e0 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 25 Jun 2026 01:35:04 +0530 Subject: [PATCH 62/64] refactor: remove service and component fields from all logs - Removed hardcoded 'service' and 'component' fields from logger initialization - Updated cmd/main.go to remove .With() call adding these fields - Updated pkg/logger/factory.go to remove service field from both JSON and Console loggers - All tests passing with cleaner log output containing only relevant contextual fields --- cmd/main.go | 4 +--- pkg/logger/factory.go | 8 -------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 7a3acd7e..5c2de886 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -73,9 +73,7 @@ func getZapLogger() *zap.Logger { zapcore.NewJSONEncoder(encoderCfg), zapcore.Lock(os.Stdout), atom, - ), zap.AddCaller()).With( - zap.String("service", "ibm-object-csi-driver"), - zap.String("component", "csi-driver")) + ), zap.AddCaller()) atom.SetLevel(zap.InfoLevel) return logger diff --git a/pkg/logger/factory.go b/pkg/logger/factory.go index 359d2e67..5add28b4 100644 --- a/pkg/logger/factory.go +++ b/pkg/logger/factory.go @@ -38,10 +38,6 @@ func NewJSONLogger(serviceName string) (*zap.Logger, error) { atom, ), zap.AddCaller()) - if serviceName != "" { - logger = logger.With(zap.String("service", serviceName)) - } - atom.SetLevel(zap.InfoLevel) return logger, nil } @@ -75,10 +71,6 @@ func NewConsoleLogger(serviceName string) (*zap.Logger, error) { atom, ), zap.AddCaller()) - if serviceName != "" { - logger = logger.With(zap.String("service", serviceName)) - } - atom.SetLevel(zap.InfoLevel) return logger, nil } From 51fecc42f9f51d93217556314110dd41f4d94d5f Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Thu, 25 Jun 2026 02:32:14 +0530 Subject: [PATCH 63/64] publish versin 0.12.47 --- .github/workflows/release.yml | 6 +++--- cos-csi-mounter/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ccb839f5..284d3b30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -113,7 +113,7 @@ jobs: env: IS_LATEST_RELEASE: 'true' - APP_VERSION: 0.12.39 + APP_VERSION: 0.12.47 steps: - name: Checkout Code @@ -139,8 +139,8 @@ jobs: /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.deb.tar.gz.sha256 /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz /home/runner/work/ibm-object-csi-driver/ibm-object-csi-driver/cos-csi-mounter/cos-csi-mounter-${{ env.APP_VERSION }}.rpm.tar.gz.sha256 - tag_name: 0.12.39 - name: 0.12.39 + tag_name: 0.12.47 + name: 0.12.47 body: | ## 🚀 What’s New - updated logging method diff --git a/cos-csi-mounter/Makefile b/cos-csi-mounter/Makefile index 6955353e..f942da6a 100644 --- a/cos-csi-mounter/Makefile +++ b/cos-csi-mounter/Makefile @@ -1,5 +1,5 @@ NAME := cos-csi-mounter -APP_VERSION := 0.12.39 +APP_VERSION := 0.12.47 BUILD_DIR := $(NAME)-$(APP_VERSION) BIN_DIR := bin From fca5bd2bfd81fcba00c54d4251dba8e1a7c85c70 Mon Sep 17 00:00:00 2001 From: balraj-singh1 Date: Wed, 1 Jul 2026 16:22:37 +0530 Subject: [PATCH 64/64] update git ignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 25c31206..5c971fd1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea -bin \ No newline at end of file +bin +tests \ No newline at end of file