132 lines
3.7 KiB
Go
132 lines
3.7 KiB
Go
|
// Copyright 2019 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 ancestry
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
|
||
|
"github.com/coreos/clair/database"
|
||
|
"github.com/coreos/clair/database/pgsql/detector"
|
||
|
"github.com/coreos/clair/database/pgsql/util"
|
||
|
"github.com/coreos/clair/pkg/commonerr"
|
||
|
log "github.com/sirupsen/logrus"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
findAncestryLayerHashes = `
|
||
|
SELECT layer.hash, ancestry_layer.ancestry_index
|
||
|
FROM layer, ancestry_layer
|
||
|
WHERE ancestry_layer.ancestry_id = $1
|
||
|
AND ancestry_layer.layer_id = layer.id
|
||
|
ORDER BY ancestry_layer.ancestry_index ASC`
|
||
|
insertAncestryLayers = `
|
||
|
INSERT INTO ancestry_layer (ancestry_id, ancestry_index, layer_id) VALUES ($1, $2, $3)
|
||
|
RETURNING id`
|
||
|
)
|
||
|
|
||
|
func FindAncestryLayerHashes(tx *sql.Tx, ancestryID int64) (map[int64]string, error) {
|
||
|
// retrieve layer indexes and hashes
|
||
|
rows, err := tx.Query(findAncestryLayerHashes, ancestryID)
|
||
|
if err != nil {
|
||
|
return nil, util.HandleError("findAncestryLayerHashes", err)
|
||
|
}
|
||
|
|
||
|
layerHashes := map[int64]string{}
|
||
|
for rows.Next() {
|
||
|
var (
|
||
|
hash string
|
||
|
index int64
|
||
|
)
|
||
|
|
||
|
if err = rows.Scan(&hash, &index); err != nil {
|
||
|
return nil, util.HandleError("findAncestryLayerHashes", err)
|
||
|
}
|
||
|
|
||
|
if _, ok := layerHashes[index]; ok {
|
||
|
// one ancestry index should correspond to only one layer
|
||
|
return nil, database.ErrInconsistent
|
||
|
}
|
||
|
|
||
|
layerHashes[index] = hash
|
||
|
}
|
||
|
|
||
|
return layerHashes, nil
|
||
|
}
|
||
|
|
||
|
// insertAncestryLayers inserts the ancestry layers along with its content into
|
||
|
// the database. The layers are 0 based indexed in the original order.
|
||
|
func InsertAncestryLayers(tx *sql.Tx, ancestryID int64, layers []int64) ([]int64, error) {
|
||
|
stmt, err := tx.Prepare(insertAncestryLayers)
|
||
|
if err != nil {
|
||
|
return nil, util.HandleError("insertAncestryLayers", err)
|
||
|
}
|
||
|
|
||
|
ancestryLayerIDs := []int64{}
|
||
|
for index, layerID := range layers {
|
||
|
var ancestryLayerID sql.NullInt64
|
||
|
if err := stmt.QueryRow(ancestryID, index, layerID).Scan(&ancestryLayerID); err != nil {
|
||
|
return nil, util.HandleError("insertAncestryLayers", commonerr.CombineErrors(err, stmt.Close()))
|
||
|
}
|
||
|
|
||
|
if !ancestryLayerID.Valid {
|
||
|
return nil, database.ErrInconsistent
|
||
|
}
|
||
|
|
||
|
ancestryLayerIDs = append(ancestryLayerIDs, ancestryLayerID.Int64)
|
||
|
}
|
||
|
|
||
|
if err := stmt.Close(); err != nil {
|
||
|
return nil, util.HandleError("insertAncestryLayers", err)
|
||
|
}
|
||
|
|
||
|
return ancestryLayerIDs, nil
|
||
|
}
|
||
|
|
||
|
func FindAncestryLayers(tx *sql.Tx, id int64) ([]database.AncestryLayer, error) {
|
||
|
detectors, err := detector.FindAllDetectors(tx)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
layerMap, err := FindAncestryLayerHashes(tx, id)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
featureMap, err := FindAncestryFeatures(tx, id, detectors)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
layers := make([]database.AncestryLayer, len(layerMap))
|
||
|
for index, layer := range layerMap {
|
||
|
// index MUST match the ancestry layer slice index.
|
||
|
if layers[index].Hash == "" && len(layers[index].Features) == 0 {
|
||
|
layers[index] = database.AncestryLayer{
|
||
|
Hash: layer,
|
||
|
Features: featureMap[index],
|
||
|
}
|
||
|
} else {
|
||
|
log.WithFields(log.Fields{
|
||
|
"ancestry ID": id,
|
||
|
"duplicated ancestry index": index,
|
||
|
}).WithError(database.ErrInconsistent).Error("ancestry layers with same ancestry_index is not allowed")
|
||
|
return nil, database.ErrInconsistent
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return layers, nil
|
||
|
}
|