add analysis coordination (with dummy analyzer)

This commit is contained in:
Alex Goodman
2020-05-18 11:59:33 -04:00
parent 4cbed05358
commit 1342cc5b06
13 changed files with 260 additions and 161 deletions
+3 -3
View File
@@ -2,13 +2,13 @@ package analyzer
import (
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/tree"
)
type Analyzer interface {
SelectFiles(scope.Scope) []file.Reference
SelectFiles([]*tree.FileTree) []file.Reference
// NOTE: one of the errors which is returned is "IterationNeeded", which indicates to the driver to
// continue with another Select/Analyze pass
Analyze(pkg.CatalogWriter, map[file.Reference]string) error
Analyze(map[file.Reference]string) ([]pkg.Package, error)
}
+47 -3
View File
@@ -1,11 +1,24 @@
package analyzer
import (
"github.com/anchore/imgbom/imgbom/analyzer/dummy"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/stereoscope/pkg/file"
"github.com/hashicorp/go-multierror"
)
var controllerInstance controller
func init() {
controllerInstance = controller{
analyzers: make([]Analyzer, 0),
}
controllerInstance.add(dummy.NewAnalyzer())
}
func Analyze(s scope.Scope) (pkg.Catalog, error) {
return controllerInstance.analyze(s)
}
type controller struct {
@@ -16,6 +29,37 @@ func (c *controller) add(a Analyzer) {
c.analyzers = append(c.analyzers, a)
}
func Add(a Analyzer) {
controllerInstance.add(a)
}
func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
catalog := pkg.NewCatalog()
fileSelection := make([]file.Reference, 0)
// ask analyzers for files to extract from the image tar
for _, a := range c.analyzers {
fileSelection = append(fileSelection, a.SelectFiles(s.Trees)...)
}
// fetch contents for requested selection by analyzers
contents, err := s.Image.MultipleFileContentsByRef(fileSelection...)
if err != nil {
return pkg.Catalog{}, err
}
// perform analysis, accumulating errors for each failed analysis
var errs error
for _, a := range c.analyzers {
packages, err := a.Analyze(contents)
// TODO: check for multiple rounds of analyses by Iterate error
if err != nil {
errs = multierror.Append(errs, err)
}
for _, p := range packages {
catalog.Add(p)
}
}
if errs != nil {
return pkg.Catalog{}, errs
}
return catalog, nil
}
+30
View File
@@ -0,0 +1,30 @@
package dummy
import (
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/tree"
)
// TODO: delete me
type Analyzer struct{}
func NewAnalyzer() *Analyzer {
return &Analyzer{}
}
func (a *Analyzer) SelectFiles(trees []*tree.FileTree) []file.Reference {
return []file.Reference{*trees[0].File("/etc/centos-release")}
}
func (a *Analyzer) Analyze(contents map[file.Reference]string) ([]pkg.Package, error) {
return []pkg.Package{
{
Name: "dummy",
Version: "1.0.0",
Type: pkg.DebPkg,
Metadata: pkg.DummyPackage{Extra: "some extra metadata"},
},
}, nil
}
+20
View File
@@ -0,0 +1,20 @@
package imgbom
import (
"github.com/anchore/imgbom/imgbom/analyzer"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/stereoscope/pkg/image"
)
// TODO: add os detection results as return value
func CatalogImage(img *image.Image, o scope.Option) (pkg.Catalog, error) {
s, err := scope.NewScope(img, o)
if err != nil {
return pkg.Catalog{}, err
}
// TODO: add OS detection here...
return analyzer.Analyze(s)
}
+11 -7
View File
@@ -1,18 +1,22 @@
package pkg
// TODO: add reader methods (by type, id, fuzzy search, etc)
type Catalog struct {
// TODO: catalog by package ID for potential indexing
catalog map[Type][]Package
Packages map[Type][]Package
}
type CatalogWriter interface {
Add(Package) error
func NewCatalog() Catalog {
return Catalog{
Packages: make(map[Type][]Package),
}
}
func (c *Catalog) Add(p Package) {
_, ok := c.catalog[p.Type]
_, ok := c.Packages[p.Type]
if !ok {
c.catalog[p.Type] = make([]Package, 0)
c.Packages[p.Type] = make([]Package, 0)
}
c.catalog[p.Type] = append(c.catalog[p.Type], p)
}
c.Packages[p.Type] = append(c.Packages[p.Type], p)
}
+6
View File
@@ -0,0 +1,6 @@
package pkg
// TODO: delete me
type DummyPackage struct {
Extra string
}
+1 -1
View File
@@ -13,4 +13,4 @@ type Package struct {
Metadata interface{}
}
// TODO: stringer...
// TODO: stringer...
+2 -2
View File
@@ -1,7 +1,7 @@
package pkg
const (
UnknownPkg uint = iota
UnknownPkg Type = iota
ApkPkg
DebPkg
JavaPkg
@@ -14,4 +14,4 @@ const (
type Type uint
// TODO: stringer...
// TODO: stringer...
+17
View File
@@ -1,5 +1,7 @@
package scope
import "strings"
const (
UnknownScope Option = iota
SquashedScope
@@ -14,6 +16,21 @@ var optionStr = []string{
"AllLayers",
}
var Options = []Option{
SquashedScope,
AllLayersScope,
}
func ParseOption(userStr string) Option {
switch strings.ToLower(userStr) {
case strings.ToLower(SquashedScope.String()):
return SquashedScope
case strings.ToLower(AllLayersScope.String()):
return AllLayersScope
}
return UnknownScope
}
func (o Option) String() string {
if int(o) >= len(optionStr) || int(o) < 0 {
return optionStr[0]