database: do insert/find layers (with their features and vulnerabilities)
This commit is contained in:
parent
2c150b015e
commit
970756cd5a
@ -2,11 +2,11 @@ package pgsql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
|
cerrors "github.com/coreos/clair/utils/errors"
|
||||||
"github.com/coreos/clair/utils/types"
|
"github.com/coreos/clair/utils/types"
|
||||||
cerrors "github.com/coreos/clair/utils/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pgSQL *pgSQL) insertFeature(feature database.Feature) (id int, err error) {
|
func (pgSQL *pgSQL) insertFeature(feature database.Feature) (int, error) {
|
||||||
if feature.Name == "" {
|
if feature.Name == "" {
|
||||||
return 0, cerrors.NewBadRequestError("could not find/insert invalid Feature")
|
return 0, cerrors.NewBadRequestError("could not find/insert invalid Feature")
|
||||||
}
|
}
|
||||||
@ -20,25 +20,29 @@ func (pgSQL *pgSQL) insertFeature(feature database.Feature) (id int, err error)
|
|||||||
// Find or create Namespace.
|
// Find or create Namespace.
|
||||||
namespaceID, err := pgSQL.insertNamespace(feature.Namespace)
|
namespaceID, err := pgSQL.insertNamespace(feature.Namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find or create Feature.
|
// Find or create Feature.
|
||||||
|
var id int
|
||||||
err = pgSQL.QueryRow(getQuery("soi_feature"), feature.Name, namespaceID).Scan(&id)
|
err = pgSQL.QueryRow(getQuery("soi_feature"), feature.Name, namespaceID).Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if pgSQL.cache != nil {
|
if pgSQL.cache != nil {
|
||||||
pgSQL.cache.Add("feature:"+feature.Name, id)
|
pgSQL.cache.Add("feature:"+feature.Name, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion) (id int, err error) {
|
func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion) (id int, err error) {
|
||||||
if featureVersion.Version.String() == "" {
|
if featureVersion.Version.String() == "" {
|
||||||
return 0, cerrors.NewBadRequestError("could not find/insert invalid FeatureVersion")
|
return 0, cerrors.NewBadRequestError("could not find/insert invalid FeatureVersion")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pgSQL.cache != nil {
|
if pgSQL.cache != nil {
|
||||||
if id, found := pgSQL.cache.Get("featureversion:" + featureVersion.Feature.Name + ":" +
|
if id, found := pgSQL.cache.Get("featureversion:" + featureVersion.Feature.Name + ":" +
|
||||||
featureVersion.Version.String()); found {
|
featureVersion.Version.String()); found {
|
||||||
return id.(int), nil
|
return id.(int), nil
|
||||||
@ -48,23 +52,23 @@ func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion)
|
|||||||
// Find or create Feature first.
|
// Find or create Feature first.
|
||||||
featureID, err := pgSQL.insertFeature(featureVersion.Feature)
|
featureID, err := pgSQL.insertFeature(featureVersion.Feature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin transaction.
|
// Begin transaction.
|
||||||
tx, err := pgSQL.Begin()
|
tx, err := pgSQL.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find or create FeatureVersion.
|
// Find or create FeatureVersion.
|
||||||
var newOrExisting string
|
var newOrExisting string
|
||||||
err = tx.QueryRow(getQuery("soi_featureversion"), featureID, featureVersion.Version).
|
err = tx.QueryRow(getQuery("soi_featureversion"), featureID, &featureVersion.Version).
|
||||||
Scan(&newOrExisting, &featureVersion.ID)
|
Scan(&newOrExisting, &featureVersion.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if newOrExisting == "exi" {
|
if newOrExisting == "exi" {
|
||||||
// That featureVersion already exists, return its id.
|
// That featureVersion already exists, return its id.
|
||||||
@ -79,14 +83,14 @@ func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion)
|
|||||||
_, err = tx.Exec(getQuery("l_share_vulnerability_fixedin_feature"))
|
_, err = tx.Exec(getQuery("l_share_vulnerability_fixedin_feature"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select every vulnerability and the fixed version that affect this Feature.
|
// Select every vulnerability and the fixed version that affect this Feature.
|
||||||
rows, err := tx.Query(getQuery("s_vulnerability_fixedin_feature"), featureID)
|
rows, err := tx.Query(getQuery("s_vulnerability_fixedin_feature"), featureID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
@ -96,17 +100,18 @@ func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion)
|
|||||||
err := rows.Scan(&fixedInID, &vulnerabilityID, &fixedInVersion)
|
err := rows.Scan(&fixedInID, &vulnerabilityID, &fixedInVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if featureVersion.Version.Compare(fixedInVersion) < 0 {
|
if featureVersion.Version.Compare(fixedInVersion) < 0 {
|
||||||
// The version of the FeatureVersion we are inserting is lower than the fixed version on this
|
// The version of the FeatureVersion we are inserting is lower than the fixed version on this
|
||||||
// Vulnerability, thus, this FeatureVersion is affected by it.
|
// Vulnerability, thus, this FeatureVersion is affected by it.
|
||||||
|
// TODO(Quentin-M): Prepare.
|
||||||
_, err := tx.Exec(getQuery("i_vulnerability_affects_featureversion"), vulnerabilityID,
|
_, err := tx.Exec(getQuery("i_vulnerability_affects_featureversion"), vulnerabilityID,
|
||||||
featureVersion.ID, fixedInID)
|
featureVersion.ID, fixedInID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +120,7 @@ func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion)
|
|||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return -1, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if pgSQL.cache != nil {
|
if pgSQL.cache != nil {
|
||||||
@ -123,5 +128,20 @@ func (pgSQL *pgSQL) insertFeatureVersion(featureVersion database.FeatureVersion)
|
|||||||
featureVersion.Version.String(), featureVersion.ID)
|
featureVersion.Version.String(), featureVersion.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, nil
|
return featureVersion.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Quentin-M): Batch me
|
||||||
|
func (pgSQL *pgSQL) insertFeatureVersions(featureVersions []database.FeatureVersion) ([]int, error) {
|
||||||
|
IDs := make([]int, 0, len(featureVersions))
|
||||||
|
|
||||||
|
for i := 0; i < len(featureVersions); i++ {
|
||||||
|
id, err := pgSQL.insertFeatureVersion(featureVersions[i])
|
||||||
|
if err != nil {
|
||||||
|
return IDs, err
|
||||||
|
}
|
||||||
|
IDs = append(IDs, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return IDs, nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
|
"github.com/coreos/clair/utils"
|
||||||
cerrors "github.com/coreos/clair/utils/errors"
|
cerrors "github.com/coreos/clair/utils/errors"
|
||||||
"github.com/guregu/null/zero"
|
"github.com/guregu/null/zero"
|
||||||
)
|
)
|
||||||
@ -11,11 +12,14 @@ import (
|
|||||||
func (pgSQL *pgSQL) FindLayer(name string, withFeatures, withVulnerabilities bool) (database.Layer, error) {
|
func (pgSQL *pgSQL) FindLayer(name string, withFeatures, withVulnerabilities bool) (database.Layer, error) {
|
||||||
// Find the layer
|
// Find the layer
|
||||||
var layer database.Layer
|
var layer database.Layer
|
||||||
var parentName sql.NullString
|
var parentID zero.Int
|
||||||
|
var parentName zero.String
|
||||||
|
var namespaceID zero.Int
|
||||||
var namespaceName sql.NullString
|
var namespaceName sql.NullString
|
||||||
|
|
||||||
err := pgSQL.QueryRow(getQuery("s_layer"), name).
|
err := pgSQL.QueryRow(getQuery("s_layer"), name).
|
||||||
Scan(&layer.ID, &layer.Name, &layer.EngineVersion, &parentName, &namespaceName)
|
Scan(&layer.ID, &layer.Name, &layer.EngineVersion, &parentID, &parentName, &namespaceID,
|
||||||
|
&namespaceName)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return layer, cerrors.ErrNotFound
|
return layer, cerrors.ErrNotFound
|
||||||
@ -24,11 +28,17 @@ func (pgSQL *pgSQL) FindLayer(name string, withFeatures, withVulnerabilities boo
|
|||||||
return layer, err
|
return layer, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentName.Valid {
|
if !parentID.IsZero() {
|
||||||
layer.Parent = &database.Layer{Name: parentName.String}
|
layer.Parent = &database.Layer{
|
||||||
|
Model: database.Model{ID: int(parentID.Int64)},
|
||||||
|
Name: parentName.String,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if namespaceName.Valid {
|
if !namespaceID.IsZero() {
|
||||||
layer.Namespace = &database.Namespace{Name: namespaceName.String}
|
layer.Namespace = &database.Namespace{
|
||||||
|
Model: database.Model{ID: int(namespaceID.Int64)},
|
||||||
|
Name: namespaceName.String,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find its features
|
// Find its features
|
||||||
@ -210,6 +220,11 @@ func (pgSQL *pgSQL) InsertLayer(layer database.Layer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
namespaceID = zero.IntFrom(int64(n))
|
namespaceID = zero.IntFrom(int64(n))
|
||||||
|
} else if layer.Namespace == nil && layer.Parent != nil {
|
||||||
|
// Import the Namespace from the parent if it has one and this layer doesn't specify one.
|
||||||
|
if layer.Parent.Namespace != nil {
|
||||||
|
namespaceID = zero.IntFrom(int64(layer.Parent.Namespace.ID))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer.ID == 0 {
|
if layer.ID == 0 {
|
||||||
@ -222,11 +237,6 @@ func (pgSQL *pgSQL) InsertLayer(layer database.Layer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parentID = zero.IntFrom(int64(layer.Parent.ID))
|
parentID = zero.IntFrom(int64(layer.Parent.ID))
|
||||||
|
|
||||||
// Import the Namespace from the parent is this layer doesn't specify one.
|
|
||||||
if zero.IsNull(namespaceID) {
|
|
||||||
namespaceID = zero.IntFrom(int64(layer.Parent.Namespace.ID))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.QueryRow(getQuery("i_layer"), layer.Name, layer.EngineVersion, parentID, namespaceID).
|
err = tx.QueryRow(getQuery("i_layer"), layer.Name, layer.EngineVersion, parentID, namespaceID).
|
||||||
@ -247,10 +257,20 @@ func (pgSQL *pgSQL) InsertLayer(layer database.Layer) error {
|
|||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all existing Layer_diff_FeatureVersion.
|
||||||
|
_, err = tx.Exec(getQuery("r_layer_diff_featureversion"), layer.ID)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Layer_diff_FeatureVersion now.
|
// Update Layer_diff_FeatureVersion now.
|
||||||
updateDiffFeatureVersions(tx, &layer, &existingLayer)
|
err = pgSQL.updateDiffFeatureVersions(tx, &layer, &existingLayer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Commit transaction.
|
// Commit transaction.
|
||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
@ -262,19 +282,73 @@ func (pgSQL *pgSQL) InsertLayer(layer database.Layer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateDiffFeatureVersions(tx *sql.Tx, layer, existingLayer *database.Layer) {
|
func (pgSQL *pgSQL) updateDiffFeatureVersions(tx *sql.Tx, layer, existingLayer *database.Layer) error {
|
||||||
// TODO
|
// add and del are the FeatureVersion diff we should insert.
|
||||||
|
var add []database.FeatureVersion
|
||||||
|
var del []database.FeatureVersion
|
||||||
|
|
||||||
if existingLayer != nil {
|
if layer.Parent == nil {
|
||||||
// We are updating a layer, we need to diff the Features with the existing Layer.
|
|
||||||
|
|
||||||
} else if layer.Parent == nil {
|
|
||||||
// There is no parent, every Features are added.
|
// There is no parent, every Features are added.
|
||||||
|
add = append(add, layer.Features...)
|
||||||
} else if layer.Parent != nil {
|
} else if layer.Parent != nil {
|
||||||
// There is a parent, we need to diff the Features with it.
|
// There is a parent, we need to diff the Features with it.
|
||||||
|
|
||||||
|
// Build name:version strctures.
|
||||||
|
layerFeaturesMapNV, layerFeaturesNV := createNV(layer.Features)
|
||||||
|
parentLayerFeaturesMapNV, parentLayerFeaturesNV := createNV(layer.Parent.Features)
|
||||||
|
|
||||||
|
// Calculate the added and deleted FeatureVersions name:version.
|
||||||
|
addNV := utils.CompareStringLists(layerFeaturesNV, parentLayerFeaturesNV)
|
||||||
|
delNV := utils.CompareStringLists(parentLayerFeaturesNV, layerFeaturesNV)
|
||||||
|
|
||||||
|
// Fill the structures containing the added and deleted FeatureVersions
|
||||||
|
for _, nv := range addNV {
|
||||||
|
add = append(add, *layerFeaturesMapNV[nv])
|
||||||
|
}
|
||||||
|
for _, nv := range delNV {
|
||||||
|
del = append(del, *parentLayerFeaturesMapNV[nv])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert FeatureVersions in the database.
|
||||||
|
addIDs, err := pgSQL.insertFeatureVersions(add)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delIDs, err := pgSQL.insertFeatureVersions(del)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert diff in the database.
|
||||||
|
if len(addIDs) > 0 {
|
||||||
|
_, err = tx.Exec(getQuery("i_layer_diff_featureversion"), layer.ID, "add", buildInputArray(addIDs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(delIDs) > 0 {
|
||||||
|
_, err = tx.Exec(getQuery("i_layer_diff_featureversion"), layer.ID, "del", buildInputArray(delIDs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNV(features []database.FeatureVersion) (map[string]*database.FeatureVersion, []string) {
|
||||||
|
mapNV := make(map[string]*database.FeatureVersion, 0)
|
||||||
|
sliceNV := make([]string, 0, len(features))
|
||||||
|
|
||||||
|
for i := 0; i < len(features); i++ {
|
||||||
|
featureVersion := &features[i]
|
||||||
|
nv := featureVersion.Feature.Name + ":" + featureVersion.Version.String()
|
||||||
|
mapNV[nv] = featureVersion
|
||||||
|
sliceNV = append(sliceNV, nv)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapNV, sliceNV
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pgSQL *pgSQL) DeleteLayer(name string) error {
|
func (pgSQL *pgSQL) DeleteLayer(name string) error {
|
||||||
|
@ -121,6 +121,8 @@ func testInsertLayerInvalid(t *testing.T, datastore database.Datastore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
||||||
|
fmt.Println("- testInsertLayerTree")
|
||||||
|
|
||||||
f1 := database.FeatureVersion{
|
f1 := database.FeatureVersion{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"},
|
Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"},
|
||||||
@ -152,7 +154,7 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
|||||||
f5 := database.FeatureVersion{
|
f5 := database.FeatureVersion{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"},
|
Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"},
|
||||||
Name: "TestInsertLayerFeature2",
|
Name: "TestInsertLayerFeature3",
|
||||||
},
|
},
|
||||||
Version: types.NewVersionUnsafe("0.57"),
|
Version: types.NewVersionUnsafe("0.57"),
|
||||||
}
|
}
|
||||||
@ -180,10 +182,11 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
|||||||
Namespace: &database.Namespace{Name: "TestInsertLayerNamespace2"},
|
Namespace: &database.Namespace{Name: "TestInsertLayerNamespace2"},
|
||||||
Features: []database.FeatureVersion{f1, f2, f3},
|
Features: []database.FeatureVersion{f1, f2, f3},
|
||||||
},
|
},
|
||||||
// This layer covers the case where the last layer doesn't provide any Feature.
|
// This layer covers the case where the last layer doesn't provide any new Feature.
|
||||||
database.Layer{
|
database.Layer{
|
||||||
Name: "TestInsertLayer4a",
|
Name: "TestInsertLayer4a",
|
||||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
||||||
|
Features: []database.FeatureVersion{f1, f2, f3},
|
||||||
},
|
},
|
||||||
// This layer covers the case where the last layer provides Features.
|
// This layer covers the case where the last layer provides Features.
|
||||||
// It also modifies the Namespace ("upgrade") but keeps some Features not upgraded, their
|
// It also modifies the Namespace ("upgrade") but keeps some Features not upgraded, their
|
||||||
@ -221,7 +224,9 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l4a := retrievedLayers["TestInsertLayer4a"]
|
l4a := retrievedLayers["TestInsertLayer4a"]
|
||||||
assert.Equal(t, "TestInsertLayerNamespace2", l4a.Namespace.Name)
|
if assert.NotNil(t, l4a.Namespace) {
|
||||||
|
assert.Equal(t, "TestInsertLayerNamespace2", l4a.Namespace.Name)
|
||||||
|
}
|
||||||
assert.Len(t, l4a.Features, 3)
|
assert.Len(t, l4a.Features, 3)
|
||||||
for _, featureVersion := range l4a.Features {
|
for _, featureVersion := range l4a.Features {
|
||||||
if cmpFV(featureVersion, f1) && cmpFV(featureVersion, f2) && cmpFV(featureVersion, f3) {
|
if cmpFV(featureVersion, f1) && cmpFV(featureVersion, f2) && cmpFV(featureVersion, f3) {
|
||||||
@ -230,9 +235,11 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l4b := retrievedLayers["TestInsertLayer4b"]
|
l4b := retrievedLayers["TestInsertLayer4b"]
|
||||||
assert.Equal(t, "TestInsertLayerNamespace3", l4a.Namespace.Name)
|
if assert.NotNil(t, l4b.Namespace) {
|
||||||
assert.Len(t, l4a.Features, 3)
|
assert.Equal(t, "TestInsertLayerNamespace3", l4b.Namespace.Name)
|
||||||
for _, featureVersion := range l4a.Features {
|
}
|
||||||
|
assert.Len(t, l4b.Features, 3)
|
||||||
|
for _, featureVersion := range l4b.Features {
|
||||||
if cmpFV(featureVersion, f2) && cmpFV(featureVersion, f5) && cmpFV(featureVersion, f6) {
|
if cmpFV(featureVersion, f2) && cmpFV(featureVersion, f5) && cmpFV(featureVersion, f6) {
|
||||||
assert.Error(t, fmt.Errorf("TestInsertLayer4a contains an unexpected package: %#v. Should contain %#v and %#v and %#v.", featureVersion, f2, f4, f6))
|
assert.Error(t, fmt.Errorf("TestInsertLayer4a contains an unexpected package: %#v. Should contain %#v and %#v and %#v.", featureVersion, f2, f4, f6))
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"bitbucket.org/liamstask/goose/lib/goose"
|
"bitbucket.org/liamstask/goose/lib/goose"
|
||||||
@ -171,18 +170,6 @@ func OpenForTest(name string, withTestData bool) (*pgSQLTest, error) {
|
|||||||
return &pgSQLTest{pgSQL: db.(*pgSQL), dataSource: dataSource, dbName: dbName}, nil
|
return &pgSQLTest{pgSQL: db.(*pgSQL), dataSource: dataSource, dbName: dbName}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildInputArray constructs a PostgreSQL input array from the specified integers.
|
|
||||||
// Useful to use the `= ANY($1::integer[])` syntax that let us use a IN clause while using
|
|
||||||
// a single placeholder.
|
|
||||||
func buildInputArray(ints []int) string {
|
|
||||||
str := "{"
|
|
||||||
for i := 0; i < len(ints)-1; i++ {
|
|
||||||
str = str + strconv.Itoa(ints[i]) + ","
|
|
||||||
}
|
|
||||||
str = str + strconv.Itoa(ints[len(ints)-1]) + "}"
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// isErrUniqueViolation determines is the given error is a unique contraint violation.
|
// isErrUniqueViolation determines is the given error is a unique contraint violation.
|
||||||
func isErrUniqueViolation(err error) bool {
|
func isErrUniqueViolation(err error) bool {
|
||||||
pqErr, ok := err.(*pq.Error)
|
pqErr, ok := err.(*pq.Error)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package pgsql
|
package pgsql
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
var queries map[string]string
|
var queries map[string]string
|
||||||
|
|
||||||
@ -28,7 +31,7 @@ func init() {
|
|||||||
queries["soi_feature"] = `
|
queries["soi_feature"] = `
|
||||||
WITH new_feature AS (
|
WITH new_feature AS (
|
||||||
INSERT INTO Feature(name, namespace_id)
|
INSERT INTO Feature(name, namespace_id)
|
||||||
SELECT CAST($1 AS VARCHAR), CAST($2 AS VARCHAR)
|
SELECT CAST($1 AS VARCHAR), CAST($2 AS INTEGER)
|
||||||
WHERE NOT EXISTS (SELECT id FROM Feature WHERE name = $1 AND namespace_id = $2)
|
WHERE NOT EXISTS (SELECT id FROM Feature WHERE name = $1 AND namespace_id = $2)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
)
|
)
|
||||||
@ -36,23 +39,25 @@ func init() {
|
|||||||
UNION
|
UNION
|
||||||
SELECT id FROM new_feature`
|
SELECT id FROM new_feature`
|
||||||
|
|
||||||
queries["l_share_vulnerability_fixedin_feature"] = `LOCK Vulnerability_FixedIn_Feature IN SHARE MODE`
|
queries["l_share_vulnerability_fixedin_feature"] = `
|
||||||
|
LOCK Vulnerability_FixedIn_Feature IN SHARE MODE
|
||||||
|
`
|
||||||
|
|
||||||
queries["soi_featureversion"] = `
|
queries["soi_featureversion"] = `
|
||||||
WITH new_featureversion AS (
|
WITH new_featureversion AS (
|
||||||
INSERT INTO FeatureVersion(feature_id, version)
|
INSERT INTO FeatureVersion(feature_id, version)
|
||||||
SELECT CAST($1 AS VARCHAR), CAST($2 AS VARCHAR)
|
SELECT CAST($1 AS INTEGER), CAST($2 AS VARCHAR)
|
||||||
WHERE NOT EXISTS (SELECT id FROM Feature WHERE feature_id = $1 AND version = $2)
|
WHERE NOT EXISTS (SELECT id FROM FeatureVersion WHERE feature_id = $1 AND version = $2)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
)
|
)
|
||||||
SELECT 'exi', id FROM Feature WHERE feature_id = $1 AND version = $2
|
SELECT 'exi', id FROM FeatureVersion WHERE feature_id = $1 AND version = $2
|
||||||
UNION
|
UNION
|
||||||
SELECT 'new', id FROM new_featureversion
|
SELECT 'new', id FROM new_featureversion
|
||||||
`
|
`
|
||||||
|
|
||||||
queries["s_vulnerability_fixedin_feature"] = `
|
queries["s_vulnerability_fixedin_feature"] = `
|
||||||
SELECT id, vulnerability_id, version FROM Vulnerability_FixedIn_Feature
|
SELECT id, vulnerability_id, version FROM Vulnerability_FixedIn_Feature
|
||||||
WHERE feature_id = ?`
|
WHERE feature_id = $1`
|
||||||
|
|
||||||
queries["i_vulnerability_affects_featureversion"] = `
|
queries["i_vulnerability_affects_featureversion"] = `
|
||||||
INSERT INTO Vulnerability_Affects_FeatureVersion(vulnerability_id,
|
INSERT INTO Vulnerability_Affects_FeatureVersion(vulnerability_id,
|
||||||
@ -60,7 +65,7 @@ func init() {
|
|||||||
|
|
||||||
// layer.go
|
// layer.go
|
||||||
queries["s_layer"] = `
|
queries["s_layer"] = `
|
||||||
SELECT l.id, l.name, l.engineversion, p.name, n.name
|
SELECT l.id, l.name, l.engineversion, p.id, p.name, n.id, n.name
|
||||||
FROM Layer l
|
FROM Layer l
|
||||||
LEFT JOIN Layer p ON l.parent_id = p.id
|
LEFT JOIN Layer p ON l.parent_id = p.id
|
||||||
LEFT JOIN Namespace n ON l.namespace_id = n.id
|
LEFT JOIN Namespace n ON l.namespace_id = n.id
|
||||||
@ -102,7 +107,8 @@ func init() {
|
|||||||
ORDER BY ltree.ordering`
|
ORDER BY ltree.ordering`
|
||||||
|
|
||||||
queries["s_featureversions_vulnerabilities"] = `
|
queries["s_featureversions_vulnerabilities"] = `
|
||||||
SELECT vafv.featureversion_id, v.id, v.name, v.description, v.link, v.severity, vn.name, vfif.version
|
SELECT vafv.featureversion_id, v.id, v.name, v.description, v.link, v.severity, vn.name,
|
||||||
|
vfif.version
|
||||||
FROM Vulnerability_Affects_FeatureVersion vafv, Vulnerability v,
|
FROM Vulnerability_Affects_FeatureVersion vafv, Vulnerability v,
|
||||||
Namespace vn, Vulnerability_FixedIn_Feature vfif
|
Namespace vn, Vulnerability_FixedIn_Feature vfif
|
||||||
WHERE vafv.featureversion_id = ANY($1::integer[])
|
WHERE vafv.featureversion_id = ANY($1::integer[])
|
||||||
@ -110,9 +116,21 @@ func init() {
|
|||||||
AND vafv.fixedin_id = vfif.id
|
AND vafv.fixedin_id = vfif.id
|
||||||
AND v.namespace_id = vn.id`
|
AND v.namespace_id = vn.id`
|
||||||
|
|
||||||
queries["i_layer"] = `INSERT INTO Layer(name, engine_version, parent_id, namespace_id) VALUES($1, $2, $3, $4) RETURNING id`
|
queries["i_layer"] = `
|
||||||
|
INSERT INTO Layer(name, engineversion, parent_id, namespace_id)
|
||||||
|
VALUES($1, $2, $3, $4) RETURNING id`
|
||||||
|
|
||||||
queries["u_layer"] = `UPDATE LAYER SET engine_version = $2, namespace_id = $3) WHERE id = $1`
|
queries["u_layer"] = `UPDATE LAYER SET engineversion = $2, namespace_id = $3) WHERE id = $1`
|
||||||
|
|
||||||
|
queries["r_layer_diff_featureversion"] = `
|
||||||
|
DELETE FROM Layer_diff_FeatureVersion
|
||||||
|
WHERE layer_id = $1`
|
||||||
|
|
||||||
|
queries["i_layer_diff_featureversion"] = `
|
||||||
|
INSERT INTO Layer_diff_FeatureVersion(layer_id, featureversion_id, modification)
|
||||||
|
SELECT $1, fv.id, $2
|
||||||
|
FROM FeatureVersion fv
|
||||||
|
WHERE fv.id = ANY($3::integer[])`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getQuery(name string) string {
|
func getQuery(name string) string {
|
||||||
@ -121,3 +139,15 @@ func getQuery(name string) string {
|
|||||||
}
|
}
|
||||||
panic(fmt.Sprintf("pgsql: unknown query %v", name))
|
panic(fmt.Sprintf("pgsql: unknown query %v", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildInputArray constructs a PostgreSQL input array from the specified integers.
|
||||||
|
// Useful to use the `= ANY($1::integer[])` syntax that let us use a IN clause while using
|
||||||
|
// a single placeholder.
|
||||||
|
func buildInputArray(ints []int) string {
|
||||||
|
str := "{"
|
||||||
|
for i := 0; i < len(ints)-1; i++ {
|
||||||
|
str = str + strconv.Itoa(ints[i]) + ","
|
||||||
|
}
|
||||||
|
str = str + strconv.Itoa(ints[len(ints)-1]) + "}"
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
@ -156,6 +156,14 @@ func detectContent(name, path, imageFormat string, parent *database.Layer) (name
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there are no feature detected, use parent's features if possible.
|
||||||
|
// TODO(Quentin-M): We eventually want to give the choice to each detectors to use none/some
|
||||||
|
// parent's Features. It would be useful for dectectors that can't find their entire result using
|
||||||
|
// one Layer.
|
||||||
|
if len(features) == 0 && parent != nil {
|
||||||
|
features = parent.Features
|
||||||
|
}
|
||||||
|
|
||||||
log.Debugf("layer %s: detected %d features", name, len(features))
|
log.Debugf("layer %s: detected %d features", name, len(features))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user