From 48427e9b8808f86929ffb905952395c91644f04e Mon Sep 17 00:00:00 2001
From: Sida Chen <git@sidac.me>
Date: Thu, 20 Sep 2018 15:39:10 -0400
Subject: [PATCH] api: Add detectors for RPC

Change the V3 implementation to accommondate the detectors.
---
 api/v3/clairpb/convert.go | 40 ++++++++++++++++++++++++++++--------
 api/v3/rpc.go             |  5 ++---
 api/v3/util.go            | 43 +++++++++++++++++++++------------------
 3 files changed, 56 insertions(+), 32 deletions(-)

diff --git a/api/v3/clairpb/convert.go b/api/v3/clairpb/convert.go
index 8414ed92..da4e9e33 100644
--- a/api/v3/clairpb/convert.go
+++ b/api/v3/clairpb/convert.go
@@ -22,6 +22,13 @@ import (
 	"github.com/coreos/clair/ext/versionfmt"
 )
 
+// DatabaseDetectorTypeMapping maps the database detector type to the integer
+// enum proto.
+var DatabaseDetectorTypeMapping = map[database.DetectorType]Detector_Type{
+	database.NamespaceDetectorType: Detector_Type(1),
+	database.FeatureDetectorType:   Detector_Type(2),
+}
+
 // PagedVulnerableAncestriesFromDatabaseModel converts database
 // PagedVulnerableAncestries to api PagedVulnerableAncestries and assigns
 // indexes to ancestries.
@@ -122,23 +129,38 @@ func VulnerabilityWithFixedInFromDatabaseModel(dbVuln database.VulnerabilityWith
 	return vuln, nil
 }
 
-// LayerFromDatabaseModel converts database layer to api layer.
-func LayerFromDatabaseModel(dbLayer database.LayerMetadata) *Layer {
-	layer := Layer{Hash: dbLayer.Hash}
-	return &layer
-}
-
 // NamespacedFeatureFromDatabaseModel converts database namespacedFeature to api Feature.
-func NamespacedFeatureFromDatabaseModel(feature database.NamespacedFeature) *Feature {
+func NamespacedFeatureFromDatabaseModel(feature database.AncestryFeature) *Feature {
 	version := feature.Feature.Version
 	if version == versionfmt.MaxVersion {
 		version = "None"
 	}
 
 	return &Feature{
-		Name:          feature.Feature.Name,
-		NamespaceName: feature.Namespace.Name,
+		Name: feature.Feature.Name,
+		Namespace: &Namespace{
+			Name:     feature.Namespace.Name,
+			Detector: DetectorFromDatabaseModel(feature.NamespaceBy),
+		},
 		VersionFormat: feature.Namespace.VersionFormat,
 		Version:       version,
+		Detector:      DetectorFromDatabaseModel(feature.FeatureBy),
 	}
 }
+
+func DetectorFromDatabaseModel(detector database.Detector) *Detector {
+	return &Detector{
+		Name:    detector.Name,
+		Version: detector.Version,
+		Type:    DatabaseDetectorTypeMapping[detector.DType],
+	}
+}
+
+func DetectorsFromDatabaseModel(dbDetectors []database.Detector) []*Detector {
+	detectors := make([]*Detector, 0, len(dbDetectors))
+	for _, d := range dbDetectors {
+		detectors = append(detectors, DetectorFromDatabaseModel(d))
+	}
+
+	return detectors
+}
diff --git a/api/v3/rpc.go b/api/v3/rpc.go
index 830bde9b..51502c2c 100644
--- a/api/v3/rpc.go
+++ b/api/v3/rpc.go
@@ -129,9 +129,8 @@ func (s *AncestryServer) GetAncestry(ctx context.Context, req *pb.GetAncestryReq
 	}
 
 	pbAncestry := &pb.GetAncestryResponse_Ancestry{
-		Name:             ancestry.Name,
-		ScannedDetectors: ancestry.ProcessedBy.Detectors,
-		ScannedListers:   ancestry.ProcessedBy.Listers,
+		Name:      ancestry.Name,
+		Detectors: pb.DetectorsFromDatabaseModel(ancestry.By),
 	}
 
 	for _, layer := range ancestry.Layers {
diff --git a/api/v3/util.go b/api/v3/util.go
index d70390d4..392a147e 100644
--- a/api/v3/util.go
+++ b/api/v3/util.go
@@ -13,8 +13,7 @@ import (
 // protobuf struct.
 func GetClairStatus(store database.Datastore) (*pb.ClairStatus, error) {
 	status := &pb.ClairStatus{
-		Listers:   clair.Processors.Listers,
-		Detectors: clair.Processors.Detectors,
+		Detectors: pb.DetectorsFromDatabaseModel(clair.EnabledDetectors),
 	}
 
 	t, firstUpdate, err := clair.GetLastUpdateTime(store)
@@ -34,19 +33,16 @@ func GetClairStatus(store database.Datastore) (*pb.ClairStatus, error) {
 
 // GetPbAncestryLayer retrieves an ancestry layer with vulnerabilities and
 // features in an ancestry based on the provided database layer.
-func GetPbAncestryLayer(session database.Session, layer database.AncestryLayer) (*pb.GetAncestryResponse_AncestryLayer, error) {
+func GetPbAncestryLayer(tx database.Session, layer database.AncestryLayer) (*pb.GetAncestryResponse_AncestryLayer, error) {
 	pbLayer := &pb.GetAncestryResponse_AncestryLayer{
 		Layer: &pb.Layer{
 			Hash: layer.Hash,
 		},
 	}
 
-	var (
-		features []database.NullableAffectedNamespacedFeature
-		err      error
-	)
-
-	if features, err = session.FindAffectedNamespacedFeatures(layer.DetectedFeatures); err != nil {
+	features := layer.GetFeatures()
+	affectedFeatures, err := tx.FindAffectedNamespacedFeatures(features)
+	if err != nil {
 		return nil, status.Error(codes.Internal, err.Error())
 	}
 
@@ -59,20 +55,27 @@ func GetPbAncestryLayer(session database.Session, layer database.AncestryLayer)
 			return nil, status.Error(codes.Internal, "ancestry feature is not found")
 		}
 
-		var (
-			pbFeature = pb.NamespacedFeatureFromDatabaseModel(feature.NamespacedFeature)
-			pbVuln    *pb.Vulnerability
-			err       error
-		)
-		for _, vuln := range feature.AffectedBy {
-			if pbVuln, err = pb.VulnerabilityWithFixedInFromDatabaseModel(vuln); err != nil {
-				return nil, status.Error(codes.Internal, err.Error())
+		for _, detectedFeature := range layer.Features {
+			if detectedFeature.NamespacedFeature != feature.NamespacedFeature {
+				continue
 			}
 
-			pbFeature.Vulnerabilities = append(pbFeature.Vulnerabilities, pbVuln)
-		}
+			var (
+				pbFeature = pb.NamespacedFeatureFromDatabaseModel(detectedFeature)
+				pbVuln    *pb.Vulnerability
+				err       error
+			)
 
-		pbLayer.DetectedFeatures = append(pbLayer.DetectedFeatures, pbFeature)
+			for _, vuln := range feature.AffectedBy {
+				if pbVuln, err = pb.VulnerabilityWithFixedInFromDatabaseModel(vuln); err != nil {
+					return nil, status.Error(codes.Internal, err.Error())
+				}
+
+				pbFeature.Vulnerabilities = append(pbFeature.Vulnerabilities, pbVuln)
+			}
+
+			pbLayer.DetectedFeatures = append(pbLayer.DetectedFeatures, pbFeature)
+		}
 	}
 
 	return pbLayer, nil