Example #1
0
File: lock.go Project: neujie/clair
// pruneLocks removes every expired locks from the database
func pruneLocks() {
	now := time.Now()

	// Delete every expired locks
	it, _ := cayley.StartPath(store, "locked").In("locked").Save("locked_until", "locked_until").Save("locked_by", "locked_by").BuildIterator().Optimize()
	defer it.Close()
	for cayley.RawNext(it) {
		tags := make(map[string]graph.Value)
		it.TagResults(tags)

		n := store.NameOf(it.Result())
		t := store.NameOf(tags["locked_until"])
		o := store.NameOf(tags["locked_by"])
		tt, _ := strconv.ParseInt(t, 10, 64)

		if now.Unix() > tt {
			log.Debugf("lock %s owned by %s has expired.", n, o)

			tr := cayley.NewTransaction()
			tr.RemoveQuad(cayley.Quad(n, "locked", "locked", ""))
			tr.RemoveQuad(cayley.Quad(n, "locked_until", t, ""))
			tr.RemoveQuad(cayley.Quad(n, "locked_by", o, ""))
			err := store.ApplyTransaction(tr)
			if err != nil {
				log.Errorf("failed transaction (pruneLocks): %s", err)
				continue
			}
			log.Debugf("lock %s has been successfully pruned.", n)
		}
	}
	if it.Err() != nil {
		log.Errorf("failed query in Unlock: %s", it.Err())
	}
}
Example #2
0
func (nd *Node) WriteData(data []byte, offset int64) error {
	if offset%BLOCK_SIZE != 0 {
		return errors.New(fmt.Sprintf("%d is not a valid offset for block size %d", offset, BLOCK_SIZE))
	}

	hash := Hash(data)
	transaction := graph.NewTransaction()

	// Determine if we already have a block for this offset
	linkName := fmt.Sprint("offset-", offset)
	if existingBlockHash := nd.BlockWithOffset(offset); existingBlockHash != "" {
		transaction.RemoveQuad(cayley.Quad(nd.Id, linkName, string(existingBlockHash), ""))
	}
	transaction.AddQuad(cayley.Quad(nd.Id, linkName, hash, ""))

	if err := nd.graph.ApplyTransaction(transaction); err != nil {
		return err
	}

	if _, err := Write(hash, data); err != nil {
		return err
	}

	return nil
}
Example #3
0
File: flag.go Project: ruo91/clair
// UpdateFlag creates a flag or update an existing flag's value
func UpdateFlag(name, value string) error {
	if name == "" || value == "" {
		log.Warning("could not insert a flag which has an empty name or value")
		return cerrors.NewBadRequestError("could not insert a flag which has an empty name or value")
	}

	// Initialize transaction
	t := cayley.NewTransaction()

	// Get current flag value
	currentValue, err := GetFlagValue(name)
	if err != nil {
		return err
	}

	// Build transaction
	name = "flag:" + name
	if currentValue != "" {
		t.RemoveQuad(cayley.Quad(name, "value", currentValue, ""))
	}
	t.AddQuad(cayley.Quad(name, "value", value, ""))

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

	// Return
	return nil
}
Example #4
0
File: lock.go Project: ruo91/clair
// pruneLocks removes every expired locks from the database
func pruneLocks() {
	now := time.Now()

	// Delete every expired locks
	tr := cayley.NewTransaction()
	it, _ := cayley.StartPath(store, "locked").In("locked").Save("locked_until", "locked_until").Save("locked_by", "locked_by").BuildIterator().Optimize()
	defer it.Close()
	for cayley.RawNext(it) {
		tags := make(map[string]graph.Value)
		it.TagResults(tags)

		n := store.NameOf(it.Result())
		t := store.NameOf(tags["locked_until"])
		o := store.NameOf(tags["locked_by"])
		tt, _ := strconv.ParseInt(t, 10, 64)

		if now.Unix() > tt {
			log.Debugf("Lock %s owned by %s has expired.", n, o)
			tr.RemoveQuad(cayley.Quad(n, "locked", "locked", ""))
			tr.RemoveQuad(cayley.Quad(n, "locked_until", t, ""))
			tr.RemoveQuad(cayley.Quad(n, "locked_by", o, ""))
		}
	}
	store.ApplyTransaction(tr)
}
Example #5
0
File: lock.go Project: ruo91/clair
// Lock tries to set a temporary lock in the database.
// If a lock already exists with the given name/owner, then the lock is renewed
//
// Lock does not block, instead, it returns true and its expiration time
// is the lock has been successfully acquired or false otherwise
func Lock(name string, duration time.Duration, owner string) (bool, time.Time) {
	pruneLocks()

	until := time.Now().Add(duration)
	untilString := strconv.FormatInt(until.Unix(), 10)

	// Try to get the expiration time of a lock with the same name/owner
	currentExpiration, err := toValue(cayley.StartPath(store, name).Has("locked_by", owner).Out("locked_until"))
	if err == nil && currentExpiration != "" {
		// Renew our lock
		if currentExpiration == untilString {
			return true, until
		}

		t := cayley.NewTransaction()
		t.RemoveQuad(cayley.Quad(name, "locked_until", currentExpiration, ""))
		t.AddQuad(cayley.Quad(name, "locked_until", untilString, ""))
		// It is not necessary to verify if the lock is ours again in the transaction
		// because if someone took it, the lock's current expiration probably changed and the transaction will fail
		return store.ApplyTransaction(t) == nil, until
	}

	t := cayley.NewTransaction()
	t.AddQuad(cayley.Quad(name, "locked", "locked", "")) // Necessary to make the transaction fails if the lock already exists (and has not been pruned)
	t.AddQuad(cayley.Quad(name, "locked_until", untilString, ""))
	t.AddQuad(cayley.Quad(name, "locked_by", owner, ""))

	glog.SetStderrThreshold("FATAL")
	success := store.ApplyTransaction(t) == nil
	glog.SetStderrThreshold("ERROR")

	return success, until
}
Example #6
0
func (ng *NodeGraph) removeNode(nd *Node) (err error) {
	if len(nd.Children()) > 0 {
		return errors.New("Can't delete node with children, must delete children first")
	}

	transaction := cayley.NewTransaction()
	if nd.Mode() > 0 {
		transaction.RemoveQuad(cayley.Quad(nd.Id, modeLink, fmt.Sprint(int(nd.Mode())), ""))
	}
	if !nd.MTime().IsZero() {
		transaction.RemoveQuad(cayley.Quad(nd.Id, mTimeLink, fmt.Sprint(nd.MTime().Format(timeFormat)), ""))
	}
	if nd.Name() != "" {
		transaction.RemoveQuad(cayley.Quad(nd.Id, nameLink, nd.Name(), ""))
	}
	if nd.Parent() != nil {
		transaction.RemoveQuad(cayley.Quad(nd.Id, parentLink, nd.Parent().Id, ""))
	}
	if nd.Type() != "" {
		transaction.RemoveQuad(cayley.Quad(nd.Id, typeLink, nd.Type(), ""))
	}

	err = ng.ApplyTransaction(transaction)

	if err == nil {
		nd.mode = os.FileMode(0)
		nd.mTime = time.Time{}
		nd.name = ""
		nd.parentId = ""
		nd.Id = ""
	}

	return
}
Example #7
0
File: lock.go Project: neujie/clair
// Unlock unlocks a lock specified by its name if I own it
func Unlock(name, owner string) {
	unlocked := 0
	it, _ := cayley.StartPath(store, name).Has("locked", "locked").Has("locked_by", owner).Save("locked_until", "locked_until").BuildIterator().Optimize()
	defer it.Close()
	for cayley.RawNext(it) {
		tags := make(map[string]graph.Value)
		it.TagResults(tags)

		t := cayley.NewTransaction()
		t.RemoveQuad(cayley.Quad(name, "locked", "locked", ""))
		t.RemoveQuad(cayley.Quad(name, "locked_until", store.NameOf(tags["locked_until"]), ""))
		t.RemoveQuad(cayley.Quad(name, "locked_by", owner, ""))
		err := store.ApplyTransaction(t)
		if err != nil {
			log.Errorf("failed transaction (Unlock): %s", err)
		}

		unlocked++
	}
	if it.Err() != nil {
		log.Errorf("failed query in Unlock: %s", it.Err())
	}
	if unlocked > 1 {
		// We should never see this, it would mean that our database doesn't ensure quad uniqueness
		// and that the entire lock system is jeopardized.
		log.Errorf("found inconsistency in Unlock: matched %d times a locked named: %s", unlocked, name)
	}
}
Example #8
0
func (nd *Node) save() (err error) {
	if nd.name == "" && nd.Name() == "" {
		return errors.New("Cannot add nameless file")
	} else if nd.Parent() == nil && nd.parentId == "" && nd.Id != RootNodeId {
		return errors.New("Cannot add file without parent")
	}

	staleQuads := graph.NewTransaction()
	newQuads := graph.NewTransaction()
	if name := nd.Name(); nd.name != name && name != "" && nd.name != "" {
		staleQuads.RemoveQuad(cayley.Quad(nd.Id, nameLink, name, ""))
	}
	if nd.name != "" && nd.name != nd.Name() {
		newQuads.AddQuad(cayley.Quad(nd.Id, nameLink, nd.name, ""))
		nd.name = ""
	}

	if mimeType := nd.Type(); nd.mimeType != mimeType && mimeType != "" && nd.mimeType != "" {
		staleQuads.RemoveQuad(cayley.Quad(nd.Id, typeLink, mimeType, ""))
	}
	if nd.mimeType != "" && nd.mimeType != nd.Type() {
		newQuads.AddQuad(cayley.Quad(nd.Id, typeLink, nd.mimeType, ""))
		nd.mimeType = ""
	}

	if mode := int(nd.Mode()); int(nd.mode) != mode && mode != 0 && int(nd.mode) != 0 {
		staleQuads.RemoveQuad(cayley.Quad(nd.Id, modeLink, fmt.Sprint(mode), ""))
	}
	if int(nd.mode) > 0 && nd.mode != nd.Mode() {
		newQuads.AddQuad(cayley.Quad(nd.Id, modeLink, fmt.Sprint(int(nd.mode)), ""))
		nd.mode = os.FileMode(0)
	}

	if mTime := nd.MTime(); nd.mTime != mTime && !mTime.IsZero() && !nd.mTime.IsZero() {
		staleQuads.RemoveQuad(cayley.Quad(nd.Id, mTimeLink, nd.MTime().Format(timeFormat), ""))
	}
	if !nd.mTime.IsZero() && nd.mTime != nd.MTime() {
		newQuads.AddQuad(cayley.Quad(nd.Id, mTimeLink, nd.mTime.Format(timeFormat), ""))
		nd.mTime = time.Time{}
	}

	if parent := nd.Parent(); parent != nil && parent.Id != nd.parentId && nd.parentId != "" {
		staleQuads.RemoveQuad(cayley.Quad(nd.Id, parentLink, nd.Parent().Id, ""))
	} else if parent != nil && parent.Id == nd.parentId {
		nd.parentId = ""
	}
	if nd.parentId != "" {
		newQuads.AddQuad(cayley.Quad(nd.Id, parentLink, nd.parentId, ""))
		nd.parentId = ""
	}

	if err = nd.graph.ApplyTransaction(staleQuads); err != nil {
		return
	} else if err = nd.graph.ApplyTransaction(newQuads); err != nil {
		return
	}

	return nil
}
Example #9
0
// MarkNotificationAsSent marks a notification as sent.
func MarkNotificationAsSent(node string) {
	// Initialize transaction
	t := cayley.NewTransaction()

	t.RemoveQuad(cayley.Quad(node, "isSent", strconv.FormatBool(false), ""))
	t.AddQuad(cayley.Quad(node, "isSent", strconv.FormatBool(true), ""))

	// Apply transaction
	store.ApplyTransaction(t)
}
Example #10
0
/*
Calls the extractArticleData package to obtain Article Data and then adds the information to the database
*/
func submitLink(w http.ResponseWriter, r *http.Request, store *cayley.Handle) {

	data := extractArticleData.GetDataFromArticle(r.FormValue("UploadLink"))

	store.AddQuad(cayley.Quad(data.Link, "has_parent", data.Parent, ""))
	store.AddQuad(cayley.Quad(data.Link, "has_date", data.Date, ""))
	store.AddQuad(cayley.Quad(data.Link, "has_content", data.Content, ""))
	store.AddQuad(cayley.Quad(data.Link, "has_title", data.Title, ""))
	store.AddQuad(cayley.Quad(data.Link, "has_description", data.Description, ""))
	store.AddQuad(cayley.Quad(data.Link, "has_image", data.Image, ""))

	for _, entity := range data.Entities {

		store.AddQuad(cayley.Quad(data.Link, "has_entity", entity.Name, ""))
		for _, class := range entity.Classes {
			store.AddQuad(cayley.Quad(entity.Name, "has_class", class, ""))

		}

		for _, category := range entity.Categories {
			store.AddQuad(cayley.Quad(entity.Name, "has_category", category, ""))
		}

	}

}
func main() {
	//graph.InitQuadStore("bolt", dbPath, nil)
	store, err := cayley.NewGraph("bolt", dbPath, nil)
	if err != nil {
		fmt.Println("error in creating database", err)
	}
	err = store.AddQuad(cayley.Quad("food", "is", "good", ""))
	// if err != nil {
	// 	fmt.Println("write error", err)
	// }
	err = store.AddQuad(cayley.Quad("nothing", "is", "good", ""))
}
Example #12
0
func (s *Storage) SaveUser(u *User) {
	s.AddQuad(cayley.Quad(u.Name, "is", "user", ""))

	p := cayley.StartPath(u.getStorage(), u.Name).Out("free at")

	iterationTime := u.IterationTime()
	it := p.BuildIterator()
	for cayley.RawNext(it) {
		s.RemoveQuad(cayley.Quad(u.Name, "free at", s.NameOf(it.Result()), ""))
	}

	s.AddQuad(cayley.Quad(u.Name, "free at", strconv.FormatInt(iterationTime, 10), ""))
}
Example #13
0
File: db.go Project: oren/user
func (db Db) AddUser(r io.Reader) (string, error) {
	uuid := uuid.NewUUID()

	if uuid == nil {
		log.Fatal("uuid is nil")
	}

	fmt.Println(uuid)

	decoder := json.NewDecoder(r)

	var u User
	err := decoder.Decode(&u)

	if err != nil {
		return "", fmt.Errorf("invalid json")
	}

	fmt.Println(u)

	ok := validEmail(u.Email)

	if !ok {
		return "", fmt.Errorf("invalid email")
	}

	db.Store.AddQuad(cayley.Quad("person:"+uuid.String(), "type", "Person", ""))
	// store.AddQuad(cayley.Quad("person:UUID", "email", u.email, ""))
	// store.AddQuad(cayley.Quad("person:UUID", "password", u.password, ""))

	return db.location, nil
}
Example #14
0
File: lock.go Project: ruo91/clair
// Unlock unlocks a lock specified by its name if I own it
func Unlock(name, owner string) {
	pruneLocks()

	t := cayley.NewTransaction()
	it, _ := cayley.StartPath(store, name).Has("locked", "locked").Has("locked_by", owner).Save("locked_until", "locked_until").BuildIterator().Optimize()
	defer it.Close()

	for cayley.RawNext(it) {
		tags := make(map[string]graph.Value)
		it.TagResults(tags)

		t.RemoveQuad(cayley.Quad(name, "locked", "locked", ""))
		t.RemoveQuad(cayley.Quad(name, "locked_until", store.NameOf(tags["locked_until"]), ""))
		t.RemoveQuad(cayley.Quad(name, "locked_by", owner, ""))
	}

	store.ApplyTransaction(t)
}
Example #15
0
func (s *localSignallingLayer) LinkServiceToAPI(serviceIdentifier string, version string, apiVersion string) error {
	var err = s.base.LinkServiceToAPI(serviceIdentifier, version, apiVersion)

	if err == nil {
		var apiNodeID = utils.CreateAPIVersionKey(apiVersion)
		var serviceVersionNodeID = utils.CreateServiceVersionKey(serviceIdentifier, version)
		err = s.graph.AddQuad(cayley.Quad(apiNodeID, utils.ContainsVersionRel, serviceVersionNodeID, ""))
		if err != nil {
			return err
		}
		err = s.graph.AddQuad(cayley.Quad(serviceVersionNodeID, utils.InApiRel, apiNodeID, ""))
		if err != nil {
			return err
		}
	}

	return err
}
Example #16
0
func (s *mgoDecorator) LinkServiceToAPI(serviceIdentifier string, version string, apiVersion string) error {
	var err = s.base.LinkServiceToAPI(serviceIdentifier, version, apiVersion)
	if err != nil {
		return err
	}

	var apiNodeID = utils.CreateAPIVersionKey(apiVersion)
	var serviceVersionNodeID = utils.CreateServiceVersionKey(serviceIdentifier, version)
	err = s.store.AddQuad(cayley.Quad(apiNodeID, utils.ContainsVersionRel, serviceVersionNodeID, ""))
	if err != nil {
		return err
	}
	err = s.store.AddQuad(cayley.Quad(serviceVersionNodeID, utils.InApiRel, apiNodeID, ""))
	if err != nil {
		return err
	}

	return nil
}
Example #17
0
// DeleteVulnerability deletes the vulnerability having the given ID
func DeleteVulnerability(id string) error {
	vulnerability, err := FindOneVulnerability(id, FieldVulnerabilityAll)
	if err != nil {
		return err
	}

	t := cayley.NewTransaction()
	t.RemoveQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityID, vulnerability.ID, ""))
	t.RemoveQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityLink, vulnerability.Link, ""))
	t.RemoveQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityPriority, string(vulnerability.Priority), ""))
	t.RemoveQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityDescription, vulnerability.Description, ""))
	for _, p := range vulnerability.FixedInNodes {
		t.RemoveQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityFixedIn, p, ""))
	}

	if err := store.ApplyTransaction(t); err != nil {
		log.Errorf("failed transaction (DeleteVulnerability): %s", err)
		return ErrTransaction
	}

	return nil
}
Example #18
0
// Healthcheck simply adds and then remove a quad in Cayley to ensure it is working
// It returns true when everything is ok
func Healthcheck() health.Status {
	var err error
	if store != nil {
		t := cayley.NewTransaction()
		q := cayley.Quad("cayley", "is", "healthy", "")
		t.AddQuad(q)
		t.RemoveQuad(q)
		glog.SetStderrThreshold("FATAL") // TODO REMOVE ME
		err = store.ApplyTransaction(t)
		glog.SetStderrThreshold("ERROR") // TODO REMOVE ME
	}

	return health.Status{IsEssential: true, IsHealthy: err == nil, Details: nil}
}
Example #19
0
// InsertNotifications stores multiple Notification in the database
// It uses the given NotificationWrapper to convert these notifications to
// something that can be stored in the database.
func InsertNotifications(notifications []Notification, wrapper NotificationWrapper) error {
	if len(notifications) == 0 {
		return nil
	}

	// Do not send notifications if there are too many of them (first update for example)
	if len(notifications) > maxNotifications {
		log.Noticef("Ignoring %d notifications", len(notifications))
		return nil
	}

	// Initialize transaction
	t := cayley.NewTransaction()

	// Iterate over all the vulnerabilities we need to insert
	for _, notification := range notifications {
		// Wrap notification
		wrappedNotification, err := wrapper.Wrap(notification)
		if err != nil {
			return err
		}

		node := "notification:" + uuid.New()
		t.AddQuad(cayley.Quad(node, FieldIs, "notification", ""))
		t.AddQuad(cayley.Quad(node, "type", wrappedNotification.Type, ""))
		t.AddQuad(cayley.Quad(node, "data", wrappedNotification.Data, ""))
		t.AddQuad(cayley.Quad(node, "isSent", strconv.FormatBool(false), ""))
	}

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

	return nil
}
Example #20
0
func (s *mgoDecorator) AddServiceVersion(serviceIdentifier string, version string) error {
	var err = s.base.AddServiceVersion(serviceIdentifier, version)
	if err != nil {
		return err
	}

	session, err := createMgoSession(s.dial)

	if err != nil {
		return fmt.Errorf("Could not establish a connection to mgo: %s", err.Error())
	}

	defer session.Close()

	c := session.DB("test").C("serviceVersions")

	var subject = serviceVersion{
		Id:      utils.CreateServiceVersionKey(serviceIdentifier, version),
		Service: serviceIdentifier,
		Version: version}
	err = c.Insert(subject)
	if err != nil {
		return err
	}
	var serviceNodeID = utils.CreateServiceDefinitionKey(serviceIdentifier)
	err = s.store.AddQuad(cayley.Quad(serviceNodeID, utils.ContainsVersionRel, subject.Id, ""))
	if err != nil {
		return err
	}
	err = s.store.AddQuad(cayley.Quad(subject.Id, utils.OfServiceRel, serviceNodeID, ""))
	if err != nil {
		return err
	}

	return nil
}
Example #21
0
File: seed.go Project: oren/user
func open() {
	path := "/tmp/user-db"
	// Initialize the database
	graph.InitQuadStore("bolt", path, nil)

	// Open and use the database
	store, err := cayley.NewGraph("bolt", path, nil)
	if err != nil {
		log.Fatalln(err)
	}

	store.AddQuad(cayley.Quad("person:sophie", "type", "Person", ""))
	store.AddQuad(cayley.Quad("person:sophie", "name", "Sophie Grégoire", ""))
	store.AddQuad(cayley.Quad("person:sophie", "born", "1974", ""))
	store.AddQuad(cayley.Quad("person:sophie", "lives in", "country:canada", ""))

	store.AddQuad(cayley.Quad("person:justin", "type", "Person", ""))
	store.AddQuad(cayley.Quad("person:justin", "name", "Justin Trudeau", ""))
	store.AddQuad(cayley.Quad("person:justin", "born", "1972", ""))
	store.AddQuad(cayley.Quad("person:justin", "lives in", "country:canada", ""))
	store.AddQuad(cayley.Quad("person:justin", "in love with", "person:sophie", ""))
}
Example #22
0
func TestToValue(t *testing.T) {
	Open("memstore", "")
	defer Close()

	// toValue()
	v, err := toValue(cayley.StartPath(store, "tests").Out("are"))
	assert.Nil(t, err, "toValue should work even if the requested path leads to nothing")
	assert.Equal(t, "", v, "toValue should return an empty string if the requested path leads to nothing")

	store.AddQuad(cayley.Quad("tests", "are", "awesome", ""))
	v, err = toValue(cayley.StartPath(store, "tests").Out("are"))
	assert.Nil(t, err, "toValue should have worked")
	assert.Equal(t, "awesome", v, "toValue did not return the expected value")

	store.AddQuad(cayley.Quad("tests", "are", "running", ""))
	v, err = toValue(cayley.StartPath(store, "tests").Out("are"))
	assert.NotNil(t, err, "toValue should return an error and an empty string if the path leads to multiple values")
	assert.Equal(t, "", v, "toValue should return an error and an empty string if the path leads to multiple values")

	// toValues()
	vs, err := toValues(cayley.StartPath(store, "CoreOS").Out(FieldIs))
	assert.Nil(t, err, "toValues should work even if the requested path leads to nothing")
	assert.Len(t, vs, 0, "toValue should return an empty array if the requested path leads to nothing")
	words := []string{"powerful", "lightweight"}
	for i, word := range words {
		store.AddQuad(cayley.Quad("CoreOS", FieldIs, word, ""))
		v, err := toValues(cayley.StartPath(store, "CoreOS").Out(FieldIs))
		assert.Nil(t, err, "toValues should have worked")
		assert.Len(t, v, i+1, "toValues did not return the right amount of values")
		for _, e := range words[:i+1] {
			assert.Contains(t, v, e, "toValues did not return the values we expected")
		}
	}

	// toValue(s)() and empty values
	store.AddQuad(cayley.Quad("bob", "likes", "", ""))
	v, err = toValue(cayley.StartPath(store, "bob").Out("likes"))
	assert.Nil(t, err, "toValue should work even if the requested path leads to nothing")
	assert.Equal(t, "", v, "toValue should return an empty string if the requested path leads to nothing")

	store.AddQuad(cayley.Quad("bob", "likes", "running", ""))
	v, err = toValue(cayley.StartPath(store, "bob").Out("likes"))
	assert.Nil(t, err, "toValue should have worked")
	assert.Equal(t, "running", v, "toValue did not return the expected value")

	store.AddQuad(cayley.Quad("bob", "likes", "swimming", ""))
	va, err := toValues(cayley.StartPath(store, "bob").Out("likes"))
	assert.Nil(t, err, "toValues should have worked")
	assert.Len(t, va, 2, "toValues should have returned 2 values")
}
Example #23
0
// InsertVulnerabilities inserts or updates several vulnerabilities in the database in one transaction
// It ensures that a vulnerability can't be fixed by two packages belonging the same Branch.
// During an update, if the vulnerability was previously fixed by a version in a branch and a new package of that branch is specified, the previous one is deleted
// Otherwise, it simply adds the defined packages, there is currently no way to delete affected packages.
//
// ID, Link, Priority and FixedInNodes fields have to be specified. Description is optionnal.
func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, error) {
	if len(vulnerabilities) == 0 {
		return []Notification{}, nil
	}

	// Create required data structure
	var err error
	t := cayley.NewTransaction()
	cachedVulnerabilities := make(map[string]*Vulnerability)
	newVulnerabilityNotifications := make(map[string]*NewVulnerabilityNotification)
	vulnerabilityPriorityIncreasedNotifications := make(map[string]*VulnerabilityPriorityIncreasedNotification)
	vulnerabilityPackageChangedNotifications := make(map[string]*VulnerabilityPackageChangedNotification)

	// Iterate over all the vulnerabilities we need to insert/update
	for _, vulnerability := range vulnerabilities {
		// Is the vulnerability already existing ?
		existingVulnerability, _ := cachedVulnerabilities[vulnerability.ID]
		if existingVulnerability == nil {
			existingVulnerability, err = FindOneVulnerability(vulnerability.ID, FieldVulnerabilityAll)
			if err != nil && err != cerrors.ErrNotFound {
				return []Notification{}, err
			}
			if existingVulnerability != nil {
				cachedVulnerabilities[vulnerability.ID] = existingVulnerability
			}
		}

		// Don't allow inserting/updating a vulnerability which is fixed in two packages of the same branch
		if len(vulnerability.FixedInNodes) > 0 {
			fixedInPackages, err := FindAllPackagesByNodes(vulnerability.FixedInNodes, []string{FieldPackageOS, FieldPackageName})
			if err != nil {
				return []Notification{}, err
			}
			fixedInBranches := make(map[string]struct{})
			for _, fixedInPackage := range fixedInPackages {
				branch := fixedInPackage.Branch()
				if _, branchExists := fixedInBranches[branch]; branchExists {
					log.Warningf("could not insert vulnerability %s because it is fixed in two packages of the same branch", vulnerability.ID)
					return []Notification{}, cerrors.NewBadRequestError("could not insert a vulnerability which is fixed in two packages of the same branch")
				}
				fixedInBranches[branch] = struct{}{}
			}
		}

		// Insert/Update vulnerability
		if existingVulnerability == nil {
			// The vulnerability does not exist, create it

			// Verify parameters
			if vulnerability.ID == "" || vulnerability.Link == "" || vulnerability.Priority == "" {
				log.Warningf("could not insert an incomplete vulnerability [ID: %s, Link: %s, Priority: %s]", vulnerability.ID, vulnerability.Link, vulnerability.Priority)
				return []Notification{}, cerrors.NewBadRequestError("Could not insert an incomplete vulnerability")
			}
			if !vulnerability.Priority.IsValid() {
				log.Warningf("could not insert a vulnerability which has an invalid priority [ID: %s, Link: %s, Priority: %s]. Valid priorities are: %v.", vulnerability.ID, vulnerability.Link, vulnerability.Priority, types.Priorities)
				return []Notification{}, cerrors.NewBadRequestError("Could not insert a vulnerability which has an invalid priority")
			}
			if len(vulnerability.FixedInNodes) == 0 {
				log.Warningf("could not insert a vulnerability which doesn't affect any package [ID: %s].", vulnerability.ID)
				return []Notification{}, cerrors.NewBadRequestError("could not insert a vulnerability which doesn't affect any package")
			}

			// Insert it
			vulnerability.Node = vulnerability.GetNode()
			cachedVulnerabilities[vulnerability.ID] = vulnerability

			t.AddQuad(cayley.Quad(vulnerability.Node, FieldIs, FieldVulnerabilityIsValue, ""))
			t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityID, vulnerability.ID, ""))
			t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityLink, vulnerability.Link, ""))
			t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityPriority, string(vulnerability.Priority), ""))
			t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityDescription, vulnerability.Description, ""))
			for _, p := range vulnerability.FixedInNodes {
				t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityFixedIn, p, ""))
			}

			// Add a notification
			newVulnerabilityNotifications[vulnerability.ID] = &NewVulnerabilityNotification{VulnerabilityID: vulnerability.ID}
		} else {
			// The vulnerability already exists, update it
			if vulnerability.Link != "" && existingVulnerability.Link != vulnerability.Link {
				t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityLink, existingVulnerability.Link, ""))
				t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityLink, vulnerability.Link, ""))
				existingVulnerability.Link = vulnerability.Link
			}
			if vulnerability.Priority != "" && vulnerability.Priority != types.Unknown && existingVulnerability.Priority != vulnerability.Priority {
				if !vulnerability.Priority.IsValid() {
					log.Warningf("could not update a vulnerability which has an invalid priority [ID: %s, Link: %s, Priority: %s]. Valid priorities are: %v.", vulnerability.ID, vulnerability.Link, vulnerability.Priority, types.Priorities)
					return []Notification{}, cerrors.NewBadRequestError("Could not update a vulnerability which has an invalid priority")
				}

				// Add a notification about the priority change if the new priority is higher and the vulnerability is not new
				if vulnerability.Priority.Compare(existingVulnerability.Priority) > 0 {
					if _, newVulnerabilityNotificationExists := newVulnerabilityNotifications[vulnerability.ID]; !newVulnerabilityNotificationExists {
						// Any priorityChangeNotification already ?
						if existingPriorityNotification, _ := vulnerabilityPriorityIncreasedNotifications[vulnerability.ID]; existingPriorityNotification != nil {
							// There is a priority change notification, replace it but keep the old priority field
							vulnerabilityPriorityIncreasedNotifications[vulnerability.ID] = &VulnerabilityPriorityIncreasedNotification{OldPriority: existingPriorityNotification.OldPriority, NewPriority: vulnerability.Priority, VulnerabilityID: existingVulnerability.ID}
						} else {
							// No previous notification, just add a new one
							vulnerabilityPriorityIncreasedNotifications[vulnerability.ID] = &VulnerabilityPriorityIncreasedNotification{OldPriority: existingVulnerability.Priority, NewPriority: vulnerability.Priority, VulnerabilityID: existingVulnerability.ID}
						}
					}
				}

				t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityPriority, string(existingVulnerability.Priority), ""))
				t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityPriority, string(vulnerability.Priority), ""))
				existingVulnerability.Priority = vulnerability.Priority
			}
			if vulnerability.Description != "" && existingVulnerability.Description != vulnerability.Description {
				t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityDescription, existingVulnerability.Description, ""))
				t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityDescription, vulnerability.Description, ""))
				existingVulnerability.Description = vulnerability.Description
			}
			if len(vulnerability.FixedInNodes) > 0 && len(utils.CompareStringLists(vulnerability.FixedInNodes, existingVulnerability.FixedInNodes)) != 0 {
				var removedNodes []string
				var addedNodes []string

				existingVulnerabilityFixedInPackages, err := FindAllPackagesByNodes(existingVulnerability.FixedInNodes, []string{FieldPackageOS, FieldPackageName, FieldPackageVersion})
				if err != nil {
					return []Notification{}, err
				}
				vulnerabilityFixedInPackages, err := FindAllPackagesByNodes(vulnerability.FixedInNodes, []string{FieldPackageOS, FieldPackageName, FieldPackageVersion})
				if err != nil {
					return []Notification{}, err
				}

				for _, p := range vulnerabilityFixedInPackages {
					// Any already existing link ?
					fixedInLinkAlreadyExists := false
					for _, ep := range existingVulnerabilityFixedInPackages {
						if *p == *ep {
							// This exact link already exists, we won't insert it again
							fixedInLinkAlreadyExists = true
						} else if p.Branch() == ep.Branch() {
							// A link to this package branch already exist and is not the same version, we will delete it
							t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityFixedIn, ep.Node, ""))

							var index int
							for i, n := range existingVulnerability.FixedInNodes {
								if n == ep.Node {
									index = i
									break
								}
							}
							existingVulnerability.FixedInNodes = append(existingVulnerability.FixedInNodes[index:], existingVulnerability.FixedInNodes[index+1:]...)
							removedNodes = append(removedNodes, ep.Node)
						}
					}

					if fixedInLinkAlreadyExists == false {
						t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityFixedIn, p.Node, ""))
						existingVulnerability.FixedInNodes = append(existingVulnerability.FixedInNodes, p.Node)
						addedNodes = append(addedNodes, p.Node)
					}
				}

				// Add notification about the FixedIn modification if the vulnerability is not new
				if len(removedNodes) > 0 || len(addedNodes) > 0 {
					if _, newVulnerabilityNotificationExists := newVulnerabilityNotifications[vulnerability.ID]; !newVulnerabilityNotificationExists {
						// Any VulnerabilityPackageChangedNotification already ?
						if existingPackageNotification, _ := vulnerabilityPackageChangedNotifications[vulnerability.ID]; existingPackageNotification != nil {
							// There is a priority change notification, add the packages modifications to it
							existingPackageNotification.AddedFixedInNodes = append(existingPackageNotification.AddedFixedInNodes, addedNodes...)
							existingPackageNotification.RemovedFixedInNodes = append(existingPackageNotification.RemovedFixedInNodes, removedNodes...)
						} else {
							// No previous notification, just add a new one
							vulnerabilityPackageChangedNotifications[vulnerability.ID] = &VulnerabilityPackageChangedNotification{VulnerabilityID: vulnerability.ID, AddedFixedInNodes: addedNodes, RemovedFixedInNodes: removedNodes}
						}
					}
				}
			}
		}
	}

	// Apply transaction
	if err = store.ApplyTransaction(t); err != nil {
		log.Errorf("failed transaction (InsertVulnerabilities): %s", err)
		return []Notification{}, ErrTransaction
	}

	// Group all notifications
	var allNotifications []Notification
	for _, notification := range newVulnerabilityNotifications {
		allNotifications = append(allNotifications, notification)
	}
	for _, notification := range vulnerabilityPriorityIncreasedNotifications {
		allNotifications = append(allNotifications, notification)
	}
	for _, notification := range vulnerabilityPackageChangedNotifications {
		allNotifications = append(allNotifications, notification)
	}

	return allNotifications, nil
}
Example #24
0
// InsertLayer insert a single layer in the database
//
// ID, and EngineVersion fields are required.
// ParentNode, OS, InstalledPackagesNodes and RemovedPackagesNodes are optional,
// SuccessorsNodes is unnecessary.
//
// The ID MUST be unique for two different layers.
//
//
// If the Layer already exists, nothing is done, except if the provided engine
// version is higher than the existing one, in which case, the OS,
// InstalledPackagesNodes and RemovedPackagesNodes fields will be replaced.
//
// The layer should only contains the newly installed/removed packages
// There is no safeguard that prevents from marking a package as newly installed
// while it has already been installed in one of its parent.
func InsertLayer(layer *Layer) error {
	// Verify parameters
	if layer.ID == "" {
		log.Warning("could not insert a layer which has an empty ID")
		return cerrors.NewBadRequestError("could not insert a layer which has an empty ID")
	}

	// Create required data structures
	t := cayley.NewTransaction()
	layer.Node = layer.GetNode()

	// Try to find an existing layer
	existingLayer, err := FindOneLayerByNode(layer.Node, FieldLayerAll)
	if err != nil && err != cerrors.ErrNotFound {
		return err
	}

	if existingLayer != nil && existingLayer.EngineVersion >= layer.EngineVersion {
		// The layer exists and has an equal or higher engine verison, do nothing
		return nil
	}

	if existingLayer == nil {
		// Create case: add permanent nodes
		t.AddQuad(cayley.Quad(layer.Node, FieldIs, FieldLayerIsValue, ""))
		t.AddQuad(cayley.Quad(layer.Node, FieldLayerID, layer.ID, ""))
		t.AddQuad(cayley.Quad(layer.Node, FieldLayerParent, layer.ParentNode, ""))
	} else {
		// Update case: remove everything before we add updated data
		t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerOS, existingLayer.OS, ""))
		for _, pkg := range existingLayer.InstalledPackagesNodes {
			t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerInstalledPackages, pkg, ""))
		}
		for _, pkg := range existingLayer.RemovedPackagesNodes {
			t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerRemovedPackages, pkg, ""))
		}
		t.RemoveQuad(cayley.Quad(layer.Node, FieldLayerEngineVersion, strconv.Itoa(existingLayer.EngineVersion), ""))
	}

	// Add OS/Packages
	t.AddQuad(cayley.Quad(layer.Node, FieldLayerOS, layer.OS, ""))
	for _, pkg := range layer.InstalledPackagesNodes {
		t.AddQuad(cayley.Quad(layer.Node, FieldLayerInstalledPackages, pkg, ""))
	}
	for _, pkg := range layer.RemovedPackagesNodes {
		t.AddQuad(cayley.Quad(layer.Node, FieldLayerRemovedPackages, pkg, ""))
	}
	t.AddQuad(cayley.Quad(layer.Node, FieldLayerEngineVersion, strconv.Itoa(layer.EngineVersion), ""))

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

	return nil
}
Example #25
0
func (a *ACL) groupAddQuad(subject, predicate, object, label string) error {
	return a.groupstore.AddQuad(cayley.Quad(subject, predicate, object, label))
}
Example #26
0
func (a *ACL) profileAddQuad(subject, predicate, object, label string) error {
	return a.profilestore.AddQuad(cayley.Quad(subject, predicate, object, label))
}
Example #27
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")
		}
	}

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

		// Is the package already existing ?
		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
		}

		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()

			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()

				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()

			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())
			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, ""))
		}

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

	// Return
	return nil
}