Skip to content

Commit

Permalink
feat: replace slow with parallel
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <knqyf263@gmail.com>
  • Loading branch information
knqyf263 committed Nov 7, 2023
1 parent 4972f06 commit ac31217
Show file tree
Hide file tree
Showing 21 changed files with 101 additions and 152 deletions.
1 change: 0 additions & 1 deletion pkg/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,6 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
SBOMSources: opts.SBOMSources,
RekorURL: opts.RekorURL,
//Platform: opts.Platform,
Slow: opts.Slow,
AWSRegion: opts.Region,
AWSEndpoint: opts.Endpoint,
FileChecksum: fileChecksum,
Expand Down
19 changes: 19 additions & 0 deletions pkg/custom/custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package custom

import (
"time"
)

type ErrorCallback func(pathname string, err error) error

// Option is a struct that allows defining a custom behavior.
// This option is only available when Trivy is used as an imported library and not through CLI flags.
type Option struct {
// Delay is the amount of time to wait between each file walk.
// Default: 0 sec
Delay time.Duration

// ErrorCallback is a function that allows users to define a custom error handling behavior while walking the filesystem.
// If not defined, the default behavior is to halt traversal on any error.
ErrorCallback ErrorCallback
}
2 changes: 1 addition & 1 deletion pkg/fanal/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var (
// AnalyzerOptions is used to initialize analyzers
type AnalyzerOptions struct {
Group Group
Slow bool
Parallel int
FilePatterns []string
DisabledAnalyzers []Type
MisconfScannerOption misconf.ScannerOption
Expand Down
8 changes: 4 additions & 4 deletions pkg/fanal/analyzer/language/java/jar/jar.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ var requiredExtensions = []string{

// javaLibraryAnalyzer analyzes jar/war/ear/par files
type javaLibraryAnalyzer struct {
client *javadb.DB
slow bool
client *javadb.DB
parallel int
}

func newJavaLibraryAnalyzer(options analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) {
return &javaLibraryAnalyzer{
slow: options.Slow,
parallel: options.Parallel,
}, nil
}

Expand Down Expand Up @@ -75,7 +75,7 @@ func (a *javaLibraryAnalyzer) PostAnalyze(ctx context.Context, input analyzer.Po
return nil
}

if err = parallel.WalkDir(ctx, input.FS, ".", a.slow, onFile, onResult); err != nil {
if err = parallel.WalkDir(ctx, input.FS, ".", a.parallel, onFile, onResult); err != nil {
return nil, xerrors.Errorf("walk dir error: %w", err)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/fanal/analyzer/language/java/jar/jar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func Test_javaLibraryAnalyzer_Analyze(t *testing.T) {
// init java-trivy-db with skip update
javadb.Init("testdata", defaultJavaDBRepository, true, false, types.RegistryOptions{Insecure: false})

a := javaLibraryAnalyzer{slow: true}
a := javaLibraryAnalyzer{parallel: 1}
ctx := context.Background()

mfs := mapfs.New()
Expand Down
19 changes: 15 additions & 4 deletions pkg/fanal/artifact/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"sort"

"github.com/aquasecurity/trivy/pkg/custom"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/misconf"
)

Expand All @@ -17,13 +17,13 @@ type Option struct {
SkipFiles []string
SkipDirs []string
FilePatterns []string
Parallel int
NoProgress bool
Insecure bool
Offline bool
AppDirs []string
SBOMSources []string
RekorURL string
Slow bool // Lower CPU and memory
AWSRegion string
AWSEndpoint string
FileChecksum bool // For SPDX
Expand All @@ -40,8 +40,19 @@ type Option struct {
SecretScannerOption analyzer.SecretScannerOption
LicenseScannerOption analyzer.LicenseScannerOption

// File walk
WalkOption walker.Option
CustomOption custom.Option
}

func (o *Option) AnalyzerOptions() analyzer.AnalyzerOptions {
return analyzer.AnalyzerOptions{
Group: o.AnalyzerGroup,
FilePatterns: o.FilePatterns,
Parallel: o.Parallel,
DisabledAnalyzers: o.DisabledAnalyzers,
MisconfScannerOption: o.MisconfScannerOption,
SecretScannerOption: o.SecretScannerOption,
LicenseScannerOption: o.LicenseScannerOption,
}
}

func (o *Option) Sort() {
Expand Down
20 changes: 6 additions & 14 deletions pkg/fanal/artifact/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/samber/lo"
"golang.org/x/exp/slices"
"golang.org/x/sync/semaphore"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
Expand All @@ -23,7 +24,6 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/parallel"
"github.com/aquasecurity/trivy/pkg/semaphore"
)

type Artifact struct {
Expand All @@ -49,15 +49,7 @@ func NewArtifact(img types.Image, c cache.ArtifactCache, opt artifact.Option) (a
return nil, xerrors.Errorf("handler init error: %w", err)
}

a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{
Group: opt.AnalyzerGroup,
Slow: opt.Slow,
FilePatterns: opt.FilePatterns,
DisabledAnalyzers: opt.DisabledAnalyzers,
MisconfScannerOption: opt.MisconfScannerOption,
SecretScannerOption: opt.SecretScannerOption,
LicenseScannerOption: opt.LicenseScannerOption,
})
a, err := analyzer.NewAnalyzerGroup(opt.AnalyzerOptions())
if err != nil {
return nil, xerrors.Errorf("analyzer group error: %w", err)
}
Expand All @@ -75,7 +67,7 @@ func NewArtifact(img types.Image, c cache.ArtifactCache, opt artifact.Option) (a
return Artifact{
image: img,
cache: c,
walker: walker.NewLayerTar(opt.SkipFiles, opt.SkipDirs, opt.Slow),
walker: walker.NewLayerTar(opt.SkipFiles, opt.SkipDirs),
analyzer: a,
configAnalyzer: ca,
handlerManager: handlerManager,
Expand Down Expand Up @@ -215,8 +207,8 @@ func (a Artifact) inspect(ctx context.Context, missingImage string, layerKeys, b
layerKeyMap map[string]LayerInfo, configFile *v1.ConfigFile) error {

var osFound types.OS
workers := lo.Ternary(a.artifactOption.Slow, 1, 5)
p := parallel.NewPipeline(workers, false, layerKeys, func(ctx context.Context, layerKey string) (any, error) {
p := parallel.NewPipeline(a.artifactOption.Parallel, false, layerKeys, func(ctx context.Context,
layerKey string) (any, error) {
layer := layerKeyMap[layerKey]

// If it is a base layer, secret scanning should not be performed.
Expand Down Expand Up @@ -268,7 +260,7 @@ func (a Artifact) inspectLayer(ctx context.Context, layerInfo LayerInfo, disable
FileChecksum: a.artifactOption.FileChecksum,
}
result := analyzer.NewAnalysisResult()
limit := semaphore.New(a.artifactOption.Slow)
limit := semaphore.NewWeighted(int64(a.artifactOption.Parallel))

// Prepare filesystem for post analysis
composite, err := a.analyzer.PostAnalyzerFS()
Expand Down
5 changes: 1 addition & 4 deletions pkg/fanal/artifact/image/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2035,11 +2035,8 @@ func TestArtifact_Inspect(t *testing.T) {
wantErr: "put layer failed",
},
{
name: "sad path, PutBlob returns an error with multiple layers and Slow enabled",
name: "sad path, PutBlob returns an error with multiple layers",
imagePath: "../../test/testdata/vuln-image.tar.gz",
artifactOpt: artifact.Option{
Slow: true,
},
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
Args: cache.ArtifactCacheMissingBlobsArgs{
ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
Expand Down
17 changes: 4 additions & 13 deletions pkg/fanal/artifact/local/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync"

"github.com/opencontainers/go-digest"
"golang.org/x/sync/semaphore"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
Expand All @@ -20,7 +21,6 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/semaphore"
)

type Artifact struct {
Expand All @@ -39,15 +39,7 @@ func NewArtifact(rootPath string, c cache.ArtifactCache, opt artifact.Option) (a
return nil, xerrors.Errorf("handler initialize error: %w", err)
}

a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{
Group: opt.AnalyzerGroup,
Slow: opt.Slow,
FilePatterns: opt.FilePatterns,
DisabledAnalyzers: opt.DisabledAnalyzers,
MisconfScannerOption: opt.MisconfScannerOption,
SecretScannerOption: opt.SecretScannerOption,
LicenseScannerOption: opt.LicenseScannerOption,
})
a, err := analyzer.NewAnalyzerGroup(opt.AnalyzerOptions())
if err != nil {
return nil, xerrors.Errorf("analyzer group error: %w", err)
}
Expand All @@ -56,10 +48,9 @@ func NewArtifact(rootPath string, c cache.ArtifactCache, opt artifact.Option) (a
rootPath: filepath.ToSlash(filepath.Clean(rootPath)),
cache: c,
walker: walker.NewFS(buildPathsToSkip(rootPath, opt.SkipFiles), buildPathsToSkip(rootPath, opt.SkipDirs),
opt.Slow, opt.WalkOption),
opt.CustomOption),
analyzer: a,
handlerManager: handlerManager,

artifactOption: opt,
}, nil
}
Expand Down Expand Up @@ -122,7 +113,7 @@ func buildPathsToSkip(base string, paths []string) []string {
func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error) {
var wg sync.WaitGroup
result := analyzer.NewAnalysisResult()
limit := semaphore.New(a.artifactOption.Slow)
limit := semaphore.NewWeighted(int64(a.artifactOption.Parallel))
opts := analyzer.AnalysisOptions{
Offline: a.artifactOption.Offline,
FileChecksum: a.artifactOption.FileChecksum,
Expand Down
15 changes: 4 additions & 11 deletions pkg/fanal/artifact/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"sync"

"golang.org/x/sync/semaphore"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
Expand All @@ -15,7 +16,6 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/handler"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/semaphore"
)

type Type string
Expand All @@ -41,7 +41,7 @@ type Storage struct {

func (a *Storage) Analyze(ctx context.Context, r *io.SectionReader) (types.BlobInfo, error) {
var wg sync.WaitGroup
limit := semaphore.New(a.artifactOption.Slow)
limit := semaphore.NewWeighted(int64(a.artifactOption.Parallel))
result := analyzer.NewAnalysisResult()

opts := analyzer.AnalysisOptions{
Expand Down Expand Up @@ -119,14 +119,7 @@ func NewArtifact(target string, c cache.ArtifactCache, opt artifact.Option) (art
if err != nil {
return nil, xerrors.Errorf("handler init error: %w", err)
}
a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{
Group: opt.AnalyzerGroup,
FilePatterns: opt.FilePatterns,
DisabledAnalyzers: opt.DisabledAnalyzers,
MisconfScannerOption: opt.MisconfScannerOption,
SecretScannerOption: opt.SecretScannerOption,
LicenseScannerOption: opt.LicenseScannerOption,
})
a, err := analyzer.NewAnalyzerGroup(opt.AnalyzerOptions())
if err != nil {
return nil, xerrors.Errorf("analyzer group error: %w", err)
}
Expand All @@ -135,7 +128,7 @@ func NewArtifact(target string, c cache.ArtifactCache, opt artifact.Option) (art
cache: c,
analyzer: a,
handlerManager: handlerManager,
walker: walker.NewVM(opt.SkipFiles, opt.SkipDirs, opt.Slow),
walker: walker.NewVM(opt.SkipFiles, opt.SkipDirs),
artifactOption: opt,
}

Expand Down
20 changes: 5 additions & 15 deletions pkg/fanal/walker/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,15 @@ import (
"golang.org/x/xerrors"

dio "github.com/aquasecurity/go-dep-parser/pkg/io"
"github.com/aquasecurity/trivy/pkg/custom"
)

type ErrorCallback func(pathname string, err error) error

// Option is a struct that allows users to define a custom walking behavior.
// This option is only available when using Trivy as an imported library and not through CLI flags.
type Option struct {
ErrorCallback ErrorCallback
Delay time.Duration
}

type FS struct {
walker
option Option
option custom.Option
}

func NewFS(skipFiles, skipDirs []string, slow bool, opt Option) FS {
func NewFS(skipFiles, skipDirs []string, opt custom.Option) FS {
if opt.ErrorCallback == nil {
opt.ErrorCallback = func(pathname string, err error) error {
switch {
Expand All @@ -43,7 +35,7 @@ func NewFS(skipFiles, skipDirs []string, slow bool, opt Option) FS {
}

return FS{
walker: newWalker(skipFiles, skipDirs, slow),
walker: newWalker(skipFiles, skipDirs),
option: opt,
}
}
Expand All @@ -70,9 +62,7 @@ func (w FS) walkDirFunc(root string, fn WalkFunc) fs.WalkDirFunc {
return err
}

if w.walker.slow {
time.Sleep(w.option.Delay)
}
time.Sleep(w.option.Delay)

filePath = filepath.Clean(filePath)

Expand Down
9 changes: 5 additions & 4 deletions pkg/fanal/walker/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package walker_test

import (
"errors"
"github.com/aquasecurity/trivy/pkg/custom"
"io"
"io/fs"
"os"
Expand All @@ -19,7 +20,7 @@ func TestDir_Walk(t *testing.T) {
type fields struct {
skipFiles []string
skipDirs []string
option walker.Option
option custom.Option
}
tests := []struct {
name string
Expand Down Expand Up @@ -74,7 +75,7 @@ func TestDir_Walk(t *testing.T) {
name: "ignore all errors",
rootDir: "testdata/fs/nosuch",
fields: fields{
option: walker.Option{
option: custom.Option{
ErrorCallback: func(pathname string, err error) error {
return nil
},
Expand All @@ -88,7 +89,7 @@ func TestDir_Walk(t *testing.T) {
name: "ignore analysis errors",
rootDir: "testdata/fs",
fields: fields{
option: walker.Option{
option: custom.Option{
ErrorCallback: func(pathname string, err error) error {
if errors.Is(err, fs.ErrClosed) {
return nil
Expand All @@ -112,7 +113,7 @@ func TestDir_Walk(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := walker.NewFS(tt.fields.skipFiles, tt.fields.skipDirs, false, tt.fields.option)
w := walker.NewFS(tt.fields.skipFiles, tt.fields.skipDirs, tt.fields.option)

err := w.Walk(tt.rootDir, tt.analyzeFn)
if tt.wantErr != "" {
Expand Down
Loading

0 comments on commit ac31217

Please sign in to comment.