2018-09-20 19:57:06 +00:00
|
|
|
// 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.
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
package database
|
2018-09-20 19:57:06 +00:00
|
|
|
|
|
|
|
import (
|
2018-11-27 18:59:07 +00:00
|
|
|
"time"
|
|
|
|
|
2018-09-20 19:57:06 +00:00
|
|
|
"github.com/deckarep/golang-set"
|
|
|
|
)
|
|
|
|
|
|
|
|
// DeduplicateNamespaces deduplicates a list of namespaces.
|
2018-10-02 14:50:53 +00:00
|
|
|
func DeduplicateNamespaces(namespaces ...Namespace) []Namespace {
|
2018-09-20 19:57:06 +00:00
|
|
|
nsSet := mapset.NewSet()
|
|
|
|
for _, ns := range namespaces {
|
|
|
|
nsSet.Add(ns)
|
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
uniqueNamespaces := make([]Namespace, 0, nsSet.Cardinality())
|
2018-09-20 19:57:06 +00:00
|
|
|
for ns := range nsSet.Iter() {
|
2018-10-02 14:50:53 +00:00
|
|
|
uniqueNamespaces = append(uniqueNamespaces, ns.(Namespace))
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
return uniqueNamespaces
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeduplicateFeatures deduplicates a list of list of features.
|
2018-10-02 14:50:53 +00:00
|
|
|
func DeduplicateFeatures(features ...Feature) []Feature {
|
2018-09-20 19:57:06 +00:00
|
|
|
fSet := mapset.NewSet()
|
|
|
|
for _, f := range features {
|
|
|
|
fSet.Add(f)
|
|
|
|
}
|
|
|
|
|
2018-10-15 20:26:24 +00:00
|
|
|
return ConvertFeatureSetToFeatures(fSet)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConvertFeatureSetToFeatures converts a feature set to an array of features
|
|
|
|
func ConvertFeatureSetToFeatures(features mapset.Set) []Feature {
|
|
|
|
uniqueFeatures := make([]Feature, 0, features.Cardinality())
|
|
|
|
for f := range features.Iter() {
|
2018-10-02 14:50:53 +00:00
|
|
|
uniqueFeatures = append(uniqueFeatures, f.(Feature))
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
return uniqueFeatures
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-19 20:33:07 +00:00
|
|
|
// FindKeyValueAndRollback wraps session FindKeyValue function with begin and
|
|
|
|
// roll back.
|
|
|
|
func FindKeyValueAndRollback(datastore Datastore, key string) (value string, ok bool, err error) {
|
|
|
|
var tx Session
|
|
|
|
tx, err = datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
value, ok, err = tx.FindKeyValue(key)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// PersistPartialLayerAndCommit wraps session PersistLayer function with begin and
|
2018-09-20 19:57:06 +00:00
|
|
|
// commit.
|
2018-10-08 17:12:18 +00:00
|
|
|
func PersistPartialLayerAndCommit(datastore Datastore, layer *Layer) error {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
if err := tx.PersistLayer(layer.Hash, layer.Features, layer.Namespaces, layer.By); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// PersistFeaturesAndCommit wraps session PersistFeaturesAndCommit function with begin and commit.
|
|
|
|
func PersistFeaturesAndCommit(datastore Datastore, features []Feature) error {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
if err := tx.PersistFeatures(features); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// PersistNamespacesAndCommit wraps session PersistNamespaces function with
|
|
|
|
// begin and commit.
|
|
|
|
func PersistNamespacesAndCommit(datastore Datastore, namespaces []Namespace) error {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
if err := tx.PersistNamespaces(namespaces); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// FindAncestryAndRollback wraps session FindAncestry function with begin and
|
|
|
|
// rollback.
|
|
|
|
func FindAncestryAndRollback(datastore Datastore, name string) (Ancestry, bool, error) {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
if err != nil {
|
2018-10-02 14:50:53 +00:00
|
|
|
return Ancestry{}, false, err
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return tx.FindAncestry(name)
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// FindLayerAndRollback wraps session FindLayer function with begin and rollback.
|
|
|
|
func FindLayerAndRollback(datastore Datastore, hash string) (layer Layer, ok bool, err error) {
|
2018-10-02 14:50:53 +00:00
|
|
|
var tx Session
|
2018-09-20 19:57:06 +00:00
|
|
|
if tx, err = datastore.Begin(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer tx.Rollback()
|
|
|
|
layer, ok, err = tx.FindLayer(hash)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeduplicateNamespacedFeatures returns a copy of all unique features in the
|
|
|
|
// input.
|
2018-10-02 14:50:53 +00:00
|
|
|
func DeduplicateNamespacedFeatures(features []NamespacedFeature) []NamespacedFeature {
|
2018-09-20 19:57:06 +00:00
|
|
|
nsSet := mapset.NewSet()
|
|
|
|
for _, ns := range features {
|
|
|
|
nsSet.Add(ns)
|
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
uniqueFeatures := make([]NamespacedFeature, 0, nsSet.Cardinality())
|
2018-09-20 19:57:06 +00:00
|
|
|
for ns := range nsSet.Iter() {
|
2018-10-02 14:50:53 +00:00
|
|
|
uniqueFeatures = append(uniqueFeatures, ns.(NamespacedFeature))
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
return uniqueFeatures
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetAncestryFeatures returns a list of unique namespaced features in the
|
|
|
|
// ancestry.
|
2018-10-02 14:50:53 +00:00
|
|
|
func GetAncestryFeatures(ancestry Ancestry) []NamespacedFeature {
|
|
|
|
features := []NamespacedFeature{}
|
2018-09-20 19:57:06 +00:00
|
|
|
for _, layer := range ancestry.Layers {
|
|
|
|
features = append(features, layer.GetFeatures()...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return DeduplicateNamespacedFeatures(features)
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// UpsertAncestryAndCommit wraps session UpsertAncestry function with begin and commit.
|
|
|
|
func UpsertAncestryAndCommit(datastore Datastore, ancestry Ancestry) error {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = tx.UpsertAncestry(ancestry); err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = tx.Commit(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// PersistNamespacedFeaturesAndCommit wraps session PersistNamespacedFeatures function
|
2018-09-20 19:57:06 +00:00
|
|
|
// with begin and commit.
|
2018-10-08 17:12:18 +00:00
|
|
|
func PersistNamespacedFeaturesAndCommit(datastore Datastore, features []NamespacedFeature) error {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tx.PersistNamespacedFeatures(features); err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:12:18 +00:00
|
|
|
// CacheRelatedVulnerabilityAndCommit wraps session CacheAffectedNamespacedFeatures
|
2018-09-20 19:57:06 +00:00
|
|
|
// function with begin and commit.
|
2018-10-08 17:12:18 +00:00
|
|
|
func CacheRelatedVulnerabilityAndCommit(datastore Datastore, features []NamespacedFeature) error {
|
2018-09-20 19:57:06 +00:00
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tx.CacheAffectedNamespacedFeatures(features); err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntersectDetectors returns the detectors in both d1 and d2.
|
2018-10-02 14:50:53 +00:00
|
|
|
func IntersectDetectors(d1 []Detector, d2 []Detector) []Detector {
|
2018-09-20 19:57:06 +00:00
|
|
|
d1Set := mapset.NewSet()
|
|
|
|
for _, d := range d1 {
|
|
|
|
d1Set.Add(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
d2Set := mapset.NewSet()
|
|
|
|
for _, d := range d2 {
|
|
|
|
d2Set.Add(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
inter := d1Set.Intersect(d2Set)
|
2018-10-02 14:50:53 +00:00
|
|
|
detectors := make([]Detector, 0, inter.Cardinality())
|
2018-09-20 19:57:06 +00:00
|
|
|
for d := range inter.Iter() {
|
2018-10-02 14:50:53 +00:00
|
|
|
detectors = append(detectors, d.(Detector))
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
return detectors
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DiffDetectors returns the detectors belongs to d1 but not d2
|
2018-10-02 14:50:53 +00:00
|
|
|
func DiffDetectors(d1 []Detector, d2 []Detector) []Detector {
|
2018-09-20 19:57:06 +00:00
|
|
|
d1Set := mapset.NewSet()
|
|
|
|
for _, d := range d1 {
|
|
|
|
d1Set.Add(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
d2Set := mapset.NewSet()
|
|
|
|
for _, d := range d2 {
|
|
|
|
d2Set.Add(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
diff := d1Set.Difference(d2Set)
|
2018-10-02 14:50:53 +00:00
|
|
|
detectors := make([]Detector, 0, diff.Cardinality())
|
2018-09-20 19:57:06 +00:00
|
|
|
for d := range diff.Iter() {
|
2018-10-02 14:50:53 +00:00
|
|
|
detectors = append(detectors, d.(Detector))
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:50:53 +00:00
|
|
|
return detectors
|
2018-09-20 19:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MergeLayers merges all content in new layer to l, where the content is
|
|
|
|
// updated.
|
2018-10-02 14:50:53 +00:00
|
|
|
func MergeLayers(l *Layer, new *Layer) *Layer {
|
2018-09-20 19:57:06 +00:00
|
|
|
featureSet := mapset.NewSet()
|
|
|
|
namespaceSet := mapset.NewSet()
|
|
|
|
bySet := mapset.NewSet()
|
|
|
|
|
|
|
|
for _, f := range l.Features {
|
|
|
|
featureSet.Add(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ns := range l.Namespaces {
|
|
|
|
namespaceSet.Add(ns)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, d := range l.By {
|
|
|
|
bySet.Add(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, feature := range new.Features {
|
|
|
|
if !featureSet.Contains(feature) {
|
|
|
|
l.Features = append(l.Features, feature)
|
|
|
|
featureSet.Add(feature)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, namespace := range new.Namespaces {
|
|
|
|
if !namespaceSet.Contains(namespace) {
|
|
|
|
l.Namespaces = append(l.Namespaces, namespace)
|
|
|
|
namespaceSet.Add(namespace)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, detector := range new.By {
|
|
|
|
if !bySet.Contains(detector) {
|
|
|
|
l.By = append(l.By, detector)
|
|
|
|
bySet.Add(detector)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return l
|
|
|
|
}
|
2018-11-27 18:59:07 +00:00
|
|
|
|
|
|
|
// AcquireLock acquires a named global lock for a duration.
|
|
|
|
//
|
|
|
|
// If renewal is true, the lock is extended as long as the same owner is
|
|
|
|
// attempting to renew the lock.
|
|
|
|
func AcquireLock(datastore Datastore, name, owner string, duration time.Duration, renewal bool) (success bool, expiration time.Time) {
|
|
|
|
// any error will cause the function to catch the error and return false.
|
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return false, time.Time{}
|
|
|
|
}
|
|
|
|
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
locked, t, err := tx.Lock(name, owner, duration, renewal)
|
|
|
|
if err != nil {
|
|
|
|
return false, time.Time{}
|
|
|
|
}
|
|
|
|
|
|
|
|
if locked {
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
|
|
return false, time.Time{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return locked, t
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReleaseLock releases a named global lock.
|
|
|
|
func ReleaseLock(datastore Datastore, name, owner string) {
|
|
|
|
tx, err := datastore.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
if err := tx.Unlock(name, owner); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|