You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
clair/pkg/dbutil/dbutil.go

289 lines
7.0 KiB

// 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 dbutil
import (
"github.com/deckarep/golang-set"
"github.com/coreos/clair/database"
)
// DeduplicateNamespaces deduplicates a list of namespaces.
func DeduplicateNamespaces(namespaces ...database.Namespace) []database.Namespace {
nsSet := mapset.NewSet()
for _, ns := range namespaces {
nsSet.Add(ns)
}
result := make([]database.Namespace, 0, nsSet.Cardinality())
for ns := range nsSet.Iter() {
result = append(result, ns.(database.Namespace))
}
return result
}
// DeduplicateFeatures deduplicates a list of list of features.
func DeduplicateFeatures(features ...database.Feature) []database.Feature {
fSet := mapset.NewSet()
for _, f := range features {
fSet.Add(f)
}
result := make([]database.Feature, 0, fSet.Cardinality())
for f := range fSet.Iter() {
result = append(result, f.(database.Feature))
}
return result
}
// PersistPartialLayer wraps session PersistLayer function with begin and
// commit.
func PersistPartialLayer(datastore database.Datastore, layer *database.Layer) error {
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()
}
// PersistFeatures wraps session PersistFeatures function with begin and commit.
func PersistFeatures(datastore database.Datastore, features []database.Feature) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if err := tx.PersistFeatures(features); err != nil {
return err
}
return tx.Commit()
}
// PersistNamespaces wraps session PersistNamespaces function with begin and
// commit.
func PersistNamespaces(datastore database.Datastore, namespaces []database.Namespace) error {
tx, err := datastore.Begin()
if err != nil {
return err
}
defer tx.Rollback()
if err := tx.PersistNamespaces(namespaces); err != nil {
return err
}
return tx.Commit()
}
// FindAncestry wraps session FindAncestry function with begin and rollback.
func FindAncestry(datastore database.Datastore, name string) (database.Ancestry, bool, error) {
tx, err := datastore.Begin()
defer tx.Rollback()
if err != nil {
return database.Ancestry{}, false, err
}
return tx.FindAncestry(name)
}
// FindLayer wraps session FindLayer function with begin and rollback.
func FindLayer(datastore database.Datastore, hash string) (layer database.Layer, ok bool, err error) {
var tx database.Session
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.
func DeduplicateNamespacedFeatures(features []database.NamespacedFeature) []database.NamespacedFeature {
nsSet := mapset.NewSet()
for _, ns := range features {
nsSet.Add(ns)
}
result := make([]database.NamespacedFeature, 0, nsSet.Cardinality())
for ns := range nsSet.Iter() {
result = append(result, ns.(database.NamespacedFeature))
}
return result
}
// GetAncestryFeatures returns a list of unique namespaced features in the
// ancestry.
func GetAncestryFeatures(ancestry database.Ancestry) []database.NamespacedFeature {
features := []database.NamespacedFeature{}
for _, layer := range ancestry.Layers {
features = append(features, layer.GetFeatures()...)
}
return DeduplicateNamespacedFeatures(features)
}
// UpsertAncestry wraps session UpsertAncestry function with begin and commit.
func UpsertAncestry(datastore database.Datastore, ancestry database.Ancestry) error {
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
}
// PersistNamespacedFeatures wraps session PersistNamespacedFeatures function
// with begin and commit.
func PersistNamespacedFeatures(datastore database.Datastore, features []database.NamespacedFeature) error {
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
}
// CacheRelatedVulnerability wraps session CacheAffectedNamespacedFeatures
// function with begin and commit.
func CacheRelatedVulnerability(datastore database.Datastore, features []database.NamespacedFeature) error {
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.
func IntersectDetectors(d1 []database.Detector, d2 []database.Detector) []database.Detector {
d1Set := mapset.NewSet()
for _, d := range d1 {
d1Set.Add(d)
}
d2Set := mapset.NewSet()
for _, d := range d2 {
d2Set.Add(d)
}
inter := d1Set.Intersect(d2Set)
result := make([]database.Detector, 0, inter.Cardinality())
for d := range inter.Iter() {
result = append(result, d.(database.Detector))
}
return result
}
// DiffDetectors returns the detectors belongs to d1 but not d2
func DiffDetectors(d1 []database.Detector, d2 []database.Detector) []database.Detector {
d1Set := mapset.NewSet()
for _, d := range d1 {
d1Set.Add(d)
}
d2Set := mapset.NewSet()
for _, d := range d2 {
d2Set.Add(d)
}
diff := d1Set.Difference(d2Set)
result := make([]database.Detector, 0, diff.Cardinality())
for d := range diff.Iter() {
result = append(result, d.(database.Detector))
}
return result
}
// MergeLayers merges all content in new layer to l, where the content is
// updated.
func MergeLayers(l *database.Layer, new *database.Layer) *database.Layer {
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
}