clair/database/detector.go
Sida Chen 5b2376498b clair: Use builder pattern for constructing ancestry
- Add Ancestry builder
- Change RPC to use the ancestry builder
2019-02-26 10:26:49 -05:00

145 lines
3.8 KiB
Go

// Copyright 2018 clair authors
//
// 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
//
// http://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 database
import (
"database/sql/driver"
"errors"
"fmt"
"strings"
)
const (
// NamespaceDetectorType is a type of detector that extracts the namespaces.
NamespaceDetectorType DetectorType = "namespace"
// FeatureDetectorType is a type of detector that extracts the features.
FeatureDetectorType DetectorType = "feature"
)
// DetectorTypes contains all detector types.
var (
DetectorTypes = []DetectorType{
NamespaceDetectorType,
FeatureDetectorType,
}
// ErrFailedToParseDetectorType is the error returned when a detector type could
// not be parsed from a string.
ErrFailedToParseDetectorType = errors.New("failed to parse DetectorType from input")
// ErrInvalidDetector is the error returned when a detector from database has
// invalid name or version or type.
ErrInvalidDetector = errors.New("the detector has invalid metadata")
)
// DetectorType is the type of a detector.
type DetectorType string
// Value implements the database/sql/driver.Valuer interface.
func (s DetectorType) Value() (driver.Value, error) {
return string(s), nil
}
// Scan implements the database/sql.Scanner interface.
func (s *DetectorType) Scan(value interface{}) error {
val, ok := value.([]byte)
if !ok {
return errors.New("could not scan a Severity from a non-string input")
}
var err error
*s, err = NewDetectorType(string(val))
if err != nil {
return err
}
return nil
}
// NewDetectorType attempts to parse a string into a standard DetectorType
// value.
func NewDetectorType(s string) (DetectorType, error) {
for _, ss := range DetectorTypes {
if strings.EqualFold(s, string(ss)) {
return ss, nil
}
}
return "", ErrFailedToParseDetectorType
}
// Valid checks if a detector type is defined.
func (s DetectorType) Valid() bool {
for _, t := range DetectorTypes {
if s == t {
return true
}
}
return false
}
// Detector is an versioned Clair extension.
type Detector struct {
// Name of an extension should be non-empty and uniquely identifies the
// extension.
Name string `json:"name"`
// Version of an extension should be non-empty.
Version string `json:"version"`
// DType is the type of the extension and should be one of the types in
// DetectorTypes.
DType DetectorType `json:"dtype"`
}
// Valid checks if all fields in the detector satisfies the spec.
func (d Detector) Valid() bool {
if d.Name == "" || d.Version == "" || !d.DType.Valid() {
return false
}
return true
}
// String returns a unique string representation of the detector.
func (d Detector) String() string {
return fmt.Sprintf("%s:%s", d.Name, d.Version)
}
// NewNamespaceDetector returns a new namespace detector.
func NewNamespaceDetector(name, version string) Detector {
return Detector{
Name: name,
Version: version,
DType: NamespaceDetectorType,
}
}
// NewFeatureDetector returns a new feature detector.
func NewFeatureDetector(name, version string) Detector {
return Detector{
Name: name,
Version: version,
DType: FeatureDetectorType,
}
}
// SerializeDetectors returns the string representation of given detectors.
func SerializeDetectors(detectors []Detector) []string {
strDetectors := []string{}
for _, d := range detectors {
strDetectors = append(strDetectors, d.String())
}
return strDetectors
}