Skip to content
Snippets Groups Projects
tapiDatabaseClient.go 6.69 KiB
Newer Older
  • Learn to ignore specific revisions
  • package database
    
    import (
    	"errors"
    	"github.com/neo4j/neo4j-go-driver/neo4j"
    	log "github.com/sirupsen/logrus"
    )
    
    type tapiDatabaseClient struct {
    	driver neo4j.Driver
    }
    
    //newTapiDatabaseClient creates a new tapiDatabaseClient with the given neo4j.Driver
    func newTapiDatabaseClient(d neo4j.Driver) *tapiDatabaseClient {
    	return &tapiDatabaseClient{
    		driver: d,
    	}
    }
    
    //storeNodeTxFunc transaction to store devices from a json.
    //relates them to a specific pnd id.
    //returns a slice of added devices
    
    func storeNodeTxFunc(id, name string, pndID int64) neo4j.TransactionWork {
    
    	return func(tx neo4j.Transaction) (interface{}, error) {
    		var nodelist []neo4j.Node
    		query :=
    			`
    			MERGE (device:Device {id: $id})
    			ON CREATE SET device.name = $name
    			WITH device
    			MATCH (pnd:PND)
    
    			WHERE id(pnd) = $pndID
    
    			MERGE (device)-[:BELONGS_TO]->(pnd)
    			RETURN device
    			`
    
    		result, err := tx.Run(query, map[string]interface{}{
    			"id":    id,
    			"name":  name,
    
    			"pndID": pndID,
    
    		})
    
    		if err != nil {
    			//TODO: handle neo4j.isServiceUnavailable()
    			return nil, err
    		}
    
    		for result.Next() {
    			nodelist = append(nodelist, result.Record().GetByIndex(0).(neo4j.Node))
    		}
    
    		if err = result.Err(); err != nil {
    			return nil, err
    		}
    
    		return nodelist, nil
    	}
    }
    
    //StoreNode stores the given nodes to the database and adds them to a
    //principle networt domain (PND). It is required for a node to belong to a PND.
    
    func (d tapiDatabaseClient) storeNode(id, name string, pndID int64) ([]neo4j.Node, error) {
    
    	session := createSession(d.driver, true)
    	defer session.Close()
    
    
    	result, err := session.WriteTransaction(storeNodeTxFunc(id, name, pndID))
    
    	if err != nil {
    		log.Info(err)
    	}
    
    	log.Info("added/updated devices (count): ", len(result.([]neo4j.Node)))
    	return result.([]neo4j.Node), err
    }
    
    //storeLinkTxFunc transaction to store links from a json.
    //creates relation between different devices.
    //returns a slice of those created relations.
    func storeLinkTxFunc(nep1Id, nep2Id string) neo4j.TransactionWork {
    	return func(tx neo4j.Transaction) (interface{}, error) {
    		var relationsList []neo4j.Relationship
    		query :=
    			`
    			MATCH (d:Device), (d2:Device)
    			WHERE d.id = $nep1Id
    			AND d2.id = $nep2Id
    			MERGE (d)-[r:connected]->(d2)
    
    			RETURN r
    
    			`
    
    		result, err := tx.Run(query, map[string]interface{}{
    			"nep1Id": nep1Id,
    			"nep2Id": nep2Id,
    		})
    
    		if err != nil {
    			//TODO: handle neo4j.isServiceUnavailable()
    			return nil, err
    		}
    
    		for result.Next() {
    			relationsList = append(relationsList, result.Record().GetByIndex(0).(neo4j.Relationship))
    		}
    
    		if err = result.Err(); err != nil {
    			return nil, err
    		}
    
    		return relationsList, nil
    	}
    }
    
    //StoreLink stores the links between nodes
    
    func (d tapiDatabaseClient) storeLink(nep1Id, nep2Id string) ([]neo4j.Relationship, error) {
    
    	session := createSession(d.driver, true)
    	defer session.Close()
    
    	result, err := session.WriteTransaction(storeLinkTxFunc(nep1Id, nep2Id))
    	if err != nil {
    		log.Info(err)
    	}
    
    	log.Info("added/updated links (count): ", len(result.([]neo4j.Relationship)))
    
    
    	return result.([]neo4j.Relationship), err
    
    }
    
    //storeNodeEdgePointsTxFunc transaction to store interfaces from a json.
    //returns count of added/updated interfaces
    func storeNodeEdgePointsTxFunc(json string) neo4j.TransactionWork {
    	return func(tx neo4j.Transaction) (interface{}, error) {
    		query :=
    			`
    			WITH apoc.convert.fromJsonMap($stringToAdd)
    			AS value
    			UNWIND value.data as i
    			MERGE (interface:Interface {id: i.object_id})
    			ON CREATE SET interface.object_type =i.object_type,
    			interface.localId = i.object_data.` + "`tapi-object-data`.name[0].value," + `
    			interface.location = i.object_data.` + "`tapi-object-data`.name[1].value," + `
    			interface.` + "`containing-node` = i.object_data.`tapi-object-data`.`containing-node`" + `
    			RETURN count(interface)
    			`
    
    		result, err := tx.Run(query, map[string]interface{}{
    			"stringToAdd": json,
    		})
    
    		if err != nil {
    			//TODO: handle neo4j.isServiceUnavailable()
    			return nil, err
    		}
    
    		if result.Next() {
    			return result.Record().GetByIndex(0), nil
    		}
    
    		return nil, errors.New("expected a record")
    	}
    }
    
    //TODO: currently this goes over each and every device/interface and adds
    //		a interface_of relation. -> do it only for the newly added interfaces
    
    //storeNodeEdgePointsRelationTxFunc transaction to create relations between interfaces and devices
    //returns count of added/updated relations
    func storeNodeEdgePointsRelationTxFunc() neo4j.TransactionWork {
    	return func(tx neo4j.Transaction) (interface{}, error) {
    		query :=
    			`
    			MATCH (d:Device), (i:Interface)
    			WHERE d.id = i.` + "`containing-node`" + `
    			MERGE (i)-[r:INTERFACE_OF]->(d)
    			RETURN count(r)
    			`
    
    		result, err := tx.Run(query, nil)
    
    		if err != nil {
    			//TODO: handle neo4j.isServiceUnavailable()
    			return nil, err
    		}
    
    		if result.Next() {
    			return result.Record().GetByIndex(0), nil
    		}
    
    		return nil, errors.New("expected a record")
    	}
    }
    
    //StoreNodeEdgePoints stores the given node edge points (interfaces)
    func (d tapiDatabaseClient) StoreNodeEdgePoints(json string) {
    	session := createSession(d.driver, true)
    	defer session.Close()
    
    	result, err := session.WriteTransaction(storeNodeEdgePointsTxFunc(json))
    	if err != nil {
    		log.Info(err)
    	}
    
    	_, err = session.WriteTransaction(storeNodeEdgePointsRelationTxFunc())
    	if err != nil {
    		log.Info(err)
    	}
    
    	log.Info("added/updated nodeEdgePoints (count): ", result)
    }
    
    
    //TODO: not implemented yet
    
    //RemovePND removes the given principle network domain by id.
    func (d tapiDatabaseClient) RemovePND(id string) {}
    
    //GetPNDByID gets a specific PND by the given ID.
    func (d tapiDatabaseClient) GetPNDByID(id string) {}
    
    //GetNodesByLabel gets all nodes that belong to a specific label.
    func (d tapiDatabaseClient) GetNodesByLabel(label string) {}
    
    //GetNodeByID gets a specific node by ID.
    func (d tapiDatabaseClient) GetNodeByID(id string) {}
    
    //RemoveNodes removes the given nodes and their relationships
    func (d tapiDatabaseClient) RemoveNodes(json string) {}
    
    //RemoveSingleNode removes the given node and their relationship by id.
    func (d tapiDatabaseClient) RemoveSingleNode(id string) {}
    
    //StoreConnections stores relations between nodes
    func (d tapiDatabaseClient) StoreConnections(json string) {}
    
    //StoreTopology creates a new network topology node. Can also create a relation
    //the new node and a existing one if desired
    func StoreTopology() {}
    
    //RemoveTopology removes the given network topology. This includes the node itself
    //aswell as the containing links and relations
    func RemoveTopology() {}
    
    //CreateTopologyRelation creates a relation between two given topologies
    func CreateTopologyRelation() {}
    
    //CreateLink creates a link between two network elements
    func CreateLink() {}
    
    //RemoveLink removes a link between two network elements
    func RemoveLink() {}