Example #1
0
// GetNode returns the node name of a Layer
// Requires the key field: ID
func (l *Layer) GetNode() string {
	return FieldLayerIsValue + ":" + utils.Hash(l.ID)
}
Example #2
0
// InsertPackages inserts several packages in the database in one transaction
// Packages are stored in linked lists, one per Branch. Each linked list has a start package and an end package defined with types.MinVersion/types.MaxVersion versions
//
// OS, Name and Version fields have to be specified.
// If the insertion is successfull, the Node field is filled and represents the graph node identifier.
func InsertPackages(packageParameters []*Package) error {
	if len(packageParameters) == 0 {
		return nil
	}

	// Verify parameters
	for _, pkg := range packageParameters {
		if pkg.OS == "" || pkg.Name == "" || pkg.Version.String() == "" {
			log.Warningf("could not insert an incomplete package [OS: %s, Name: %s, Version: %s]", pkg.OS, pkg.Name, pkg.Version)
			return cerrors.NewBadRequestError("could not insert an incomplete package")
		}
	}

	// Create required data structures
	t := cayley.NewTransaction()
	packagesInTransaction := 0
	cachedPackagesByBranch := make(map[string]map[string]*Package)

	// Iterate over all the packages we need to insert
	for _, packageParameter := range packageParameters {
		branch := packageParameter.Branch()

		// Is the package already existing ?
		if _, branchExistsLocally := cachedPackagesByBranch[branch]; branchExistsLocally {
			if pkg, _ := cachedPackagesByBranch[branch][packageParameter.Key()]; pkg != nil {
				packageParameter.Node = pkg.Node
				continue
			}
		} else {
			cachedPackagesByBranch[branch] = make(map[string]*Package)
		}
		pkg, err := FindOnePackage(packageParameter.OS, packageParameter.Name, packageParameter.Version, []string{})
		if err != nil && err != cerrors.ErrNotFound {
			return err
		}
		if pkg != nil {
			packageParameter.Node = pkg.Node
			continue
		}

		// Get all packages of the same branch (both from local cache and database)
		branchPackages, err := FindAllPackagesByBranch(packageParameter.OS, packageParameter.Name, []string{FieldPackageOS, FieldPackageName, FieldPackageVersion, FieldPackageNextVersion})
		if err != nil {
			return err
		}
		for _, p := range cachedPackagesByBranch[branch] {
			branchPackages = append(branchPackages, p)
		}

		if len(branchPackages) == 0 {
			// The branch does not exist yet
			insertingStartPackage := packageParameter.Version == types.MinVersion
			insertingEndPackage := packageParameter.Version == types.MaxVersion

			// Create and insert a end package
			endPackage := &Package{
				OS:      packageParameter.OS,
				Name:    packageParameter.Name,
				Version: types.MaxVersion,
			}
			endPackage.Node = endPackage.GetNode()
			cachedPackagesByBranch[branch][endPackage.Key()] = endPackage

			t.AddQuad(cayley.Quad(endPackage.Node, FieldIs, FieldPackageIsValue, ""))
			t.AddQuad(cayley.Quad(endPackage.Node, FieldPackageOS, endPackage.OS, ""))
			t.AddQuad(cayley.Quad(endPackage.Node, FieldPackageName, endPackage.Name, ""))
			t.AddQuad(cayley.Quad(endPackage.Node, FieldPackageVersion, endPackage.Version.String(), ""))
			t.AddQuad(cayley.Quad(endPackage.Node, FieldPackageNextVersion, "", ""))

			// Create the inserted package if it is different than a start/end package
			var newPackage *Package
			if !insertingStartPackage && !insertingEndPackage {
				newPackage = &Package{
					OS:      packageParameter.OS,
					Name:    packageParameter.Name,
					Version: packageParameter.Version,
				}
				newPackage.Node = newPackage.GetNode()
				cachedPackagesByBranch[branch][newPackage.Key()] = newPackage

				t.AddQuad(cayley.Quad(newPackage.Node, FieldIs, FieldPackageIsValue, ""))
				t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageOS, newPackage.OS, ""))
				t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageName, newPackage.Name, ""))
				t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageVersion, newPackage.Version.String(), ""))
				t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageNextVersion, endPackage.Node, ""))

				packageParameter.Node = newPackage.Node
			}

			// Create and insert a start package
			startPackage := &Package{
				OS:      packageParameter.OS,
				Name:    packageParameter.Name,
				Version: types.MinVersion,
			}
			startPackage.Node = startPackage.GetNode()
			cachedPackagesByBranch[branch][startPackage.Key()] = startPackage

			t.AddQuad(cayley.Quad(startPackage.Node, FieldIs, FieldPackageIsValue, ""))
			t.AddQuad(cayley.Quad(startPackage.Node, FieldPackageOS, startPackage.OS, ""))
			t.AddQuad(cayley.Quad(startPackage.Node, FieldPackageName, startPackage.Name, ""))
			t.AddQuad(cayley.Quad(startPackage.Node, FieldPackageVersion, startPackage.Version.String(), ""))
			if !insertingStartPackage && !insertingEndPackage {
				t.AddQuad(cayley.Quad(startPackage.Node, FieldPackageNextVersion, newPackage.Node, ""))
			} else {
				t.AddQuad(cayley.Quad(startPackage.Node, FieldPackageNextVersion, endPackage.Node, ""))
			}

			// Set package node
			if insertingEndPackage {
				packageParameter.Node = endPackage.Node
			} else if insertingStartPackage {
				packageParameter.Node = startPackage.Node
			}
		} else {
			// The branch already exists

			// Create the package
			newPackage := &Package{OS: packageParameter.OS, Name: packageParameter.Name, Version: packageParameter.Version}
			newPackage.Node = "package:" + utils.Hash(newPackage.Key())
			cachedPackagesByBranch[branch][newPackage.Key()] = newPackage
			packageParameter.Node = newPackage.Node

			t.AddQuad(cayley.Quad(newPackage.Node, FieldIs, FieldPackageIsValue, ""))
			t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageOS, newPackage.OS, ""))
			t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageName, newPackage.Name, ""))
			t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageVersion, newPackage.Version.String(), ""))

			// Sort branchPackages by version (including the new package)
			branchPackages = append(branchPackages, newPackage)
			sort.Sort(ByVersion(branchPackages))

			// Find my prec/succ GraphID in the sorted slice now
			newPackageKey := newPackage.Key()
			var pred, succ *Package
			var found bool
			for _, p := range branchPackages {
				equal := p.Key() == newPackageKey
				if !equal && !found {
					pred = p
				} else if found {
					succ = p
					break
				} else if equal {
					found = true
					continue
				}
			}
			if pred == nil || succ == nil {
				log.Warningf("could not find any package predecessor/successor of: [OS: %s, Name: %s, Version: %s].", packageParameter.OS, packageParameter.Name, packageParameter.Version)
				return cerrors.NewBadRequestError("could not find package predecessor/successor")
			}

			// Link the new packages with the branch
			t.RemoveQuad(cayley.Quad(pred.Node, FieldPackageNextVersion, succ.Node, ""))

			pred.NextVersionNode = newPackage.Node
			t.AddQuad(cayley.Quad(pred.Node, FieldPackageNextVersion, newPackage.Node, ""))

			newPackage.NextVersionNode = succ.Node
			t.AddQuad(cayley.Quad(newPackage.Node, FieldPackageNextVersion, succ.Node, ""))
		}

		packagesInTransaction = packagesInTransaction + 1

		// Apply transaction
		if packagesInTransaction >= insertPackagesBatchSize {
			if err := store.ApplyTransaction(t); err != nil {
				log.Errorf("failed transaction (InsertPackages): %s", err)
				return ErrTransaction
			}

			t = cayley.NewTransaction()
			cachedPackagesByBranch = make(map[string]map[string]*Package)
			packagesInTransaction = 0
		}
	}

	// Apply transaction
	if packagesInTransaction > 0 {
		if err := store.ApplyTransaction(t); err != nil {
			log.Errorf("failed transaction (InsertPackages): %s", err)
			return ErrTransaction
		}
	}

	// Return
	return nil
}
Example #3
0
// GetNode returns an unique identifier for the graph node
// Requires the key fields: OS, Name, Version
func (p *Package) GetNode() string {
	return FieldPackageIsValue + ":" + utils.Hash(p.Key())
}
Example #4
0
// GetNode returns an unique identifier for the graph node
// Requires the key field: ID
func (v *Vulnerability) GetNode() string {
	return FieldVulnerabilityIsValue + ":" + utils.Hash(v.ID)
}