From eba48afd583391cef346e45a176aa5a6d77b704f Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Fri, 26 Sep 2025 12:25:44 +0400 Subject: [PATCH] feat: add documentation URL for database lock errors (#9531) --- cmd/trivy/main.go | 3 +-- pkg/cache/fs.go | 3 ++- pkg/commands/artifact/run.go | 7 ------- pkg/commands/run.go | 33 +++++++++++++++++++++++++++++++++ pkg/k8s/commands/run.go | 11 +---------- 5 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 pkg/commands/run.go diff --git a/cmd/trivy/main.go b/cmd/trivy/main.go index 5422a2d81e..33bd254165 100644 --- a/cmd/trivy/main.go +++ b/cmd/trivy/main.go @@ -47,6 +47,5 @@ func run() error { // Set up signal handling for graceful shutdown ctx := commands.NotifyContext(context.Background()) - app := commands.NewApp() - return app.ExecuteContext(ctx) + return commands.Run(ctx) } diff --git a/pkg/cache/fs.go b/pkg/cache/fs.go index 082200950a..fb331b45ef 100644 --- a/pkg/cache/fs.go +++ b/pkg/cache/fs.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/go-multierror" bolt "go.etcd.io/bbolt" + bberrors "go.etcd.io/bbolt/errors" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -34,7 +35,7 @@ func NewFSCache(cacheDir string) (FSCache, error) { }) if err != nil { // Check if the error is due to timeout (database locked by another process) - if errors.Is(err, bolt.ErrTimeout) { + if errors.Is(err, bberrors.ErrTimeout) { return FSCache{}, xerrors.Errorf("cache may be in use by another process: %w", err) } return FSCache{}, xerrors.Errorf("unable to open cache DB: %w", err) diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 8cbb6fd9d2..555be1ec73 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -367,13 +367,6 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err ctx, cancel := context.WithTimeout(ctx, opts.Timeout) defer cancel() - defer func() { - if errors.Is(err, context.DeadlineExceeded) { - // e.g. https://trivy.dev/latest/docs/configuration/ - log.WarnContext(ctx, fmt.Sprintf("Provide a higher timeout value, see %s", doc.URL("/docs/configuration/", ""))) - } - }() - if opts.GenerateDefaultConfig { log.Info("Writing the default config to trivy-default.yaml...") diff --git a/pkg/commands/run.go b/pkg/commands/run.go new file mode 100644 index 0000000000..718af0912f --- /dev/null +++ b/pkg/commands/run.go @@ -0,0 +1,33 @@ +package commands + +import ( + "context" + "errors" + "fmt" + + bberrors "go.etcd.io/bbolt/errors" + + "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/version/doc" +) + +const ( + troubleshootingDocPath = "/docs/references/troubleshooting/" + lockDocFragment = "database-and-cache-lock-errors" + timeoutDocFragment = "timeout" +) + +// Run builds the CLI application and executes it with centralized error handling. +func Run(ctx context.Context) error { + app := NewApp() + if err := app.ExecuteContext(ctx); err != nil { + if errors.Is(err, context.DeadlineExceeded) { + log.WarnContext(ctx, fmt.Sprintf("Provide a higher timeout value, see %s", doc.URL(troubleshootingDocPath, timeoutDocFragment))) + } + if errors.Is(err, bberrors.ErrTimeout) { + log.ErrorContext(ctx, fmt.Sprintf("Failed to acquire cache or database lock, see %s for troubleshooting", doc.URL(troubleshootingDocPath, lockDocFragment))) + } + return err + } + return nil +} diff --git a/pkg/k8s/commands/run.go b/pkg/k8s/commands/run.go index 38eb171f6c..15f2e68419 100644 --- a/pkg/k8s/commands/run.go +++ b/pkg/k8s/commands/run.go @@ -3,7 +3,6 @@ package commands import ( "context" "errors" - "fmt" "github.com/spf13/viper" "golang.org/x/xerrors" @@ -19,7 +18,6 @@ import ( "github.com/aquasecurity/trivy/pkg/k8s/scanner" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" - "github.com/aquasecurity/trivy/pkg/version/doc" ) // Run runs a k8s scan @@ -37,14 +35,7 @@ func Run(ctx context.Context, args []string, opts flag.Options) error { return xerrors.Errorf("failed getting k8s cluster: %w", err) } ctx, cancel := context.WithTimeout(ctx, opts.Timeout) - - defer func() { - cancel() - if errors.Is(err, context.DeadlineExceeded) { - // e.g. https://trivy.dev/latest/docs/configuration - log.WarnContext(ctx, fmt.Sprintf("Provide a higher timeout value, see %s", doc.URL("/docs/configuration/", ""))) - } - }() + defer cancel() opts.K8sVersion = cluster.GetClusterVersion() return clusterRun(ctx, opts, cluster) }