diff --git a/database/database.go b/database/database.go index 2ac409b3eec9f681995be93d71bdcee7f7df5290..bd8dfd6dfed5ecfb1f1b5baff169380769711f1f 100644 --- a/database/database.go +++ b/database/database.go @@ -2,6 +2,7 @@ package database import ( "code.fbi.h-da.de/cocsn/gosdn/log" + "errors" "github.com/neo4j/neo4j-go-driver/neo4j" ) @@ -12,9 +13,9 @@ type Database struct { //PND is a principle network domain type PND struct { - name string - description string - southboundInterfaces []string + name string + description string + interfaces []string } //NewDatabaseClient creates a database client @@ -57,36 +58,53 @@ func createSession(driver neo4j.Driver, write bool) neo4j.Session { session, err := driver.NewSession(sessionConfig) if err != nil { - log.Info("failed creating database session:", err) + log.Info(err) } return session } +//storePndTxFunc transaction to store a pnd in the database +func storePndTxFunc(name, description string, interfaces []string) neo4j.TransactionWork { + return func(tx neo4j.Transaction) (interface{}, error) { + query := + ` + MERGE (pnd:PND {name: $name}) + ON CREATE SET pnd.description = $description, + pnd.interfaces = $interfaces + RETURN pnd + ` + + result, err := tx.Run(query, map[string]interface{}{ + "name": name, + "description": description, + "interfaces": interfaces, + }) + + if err != nil { + return nil, err + } + + if result.Next() { + log.Info(result.Consume()) + return result.Record().GetByIndex(0), nil + } + + return nil, errors.New("expected a record") + } +} + //StorePND stores the given principle network domain -func (d Database) StorePND(pnd *PND) { +func (d Database) StorePND(pnd *PND) neo4j.Node { session := createSession(d.driver, true) defer session.Close() - query := - ` - MERGE (pnd:PND {name: $name}) - ON CREATE SET pnd.description = $description, - pnd.southboundInterfaces = $southboundInterfaces - ` - //refactor map[string]interface... in own function - _, err := session.Run( - query, map[string]interface{}{ - "name": pnd.name, - "description": pnd.description, - "southboundInterfaces": pnd.southboundInterfaces, - }) - + result, err := session.WriteTransaction(storePndTxFunc(pnd.name, pnd.description, pnd.interfaces)) if err != nil { - log.Info("failed storing PND into database:", err) + log.Info(err) } - log.Info("successfully added PND into database") + return result.(neo4j.Node) } //RemovePND removes the given principle network domain by id. @@ -98,44 +116,65 @@ func (d Database) GetNodesByLabel(label string) {} func (d Database) GetDeviceByID(id string) {} +func storeNodesTxFunc(json string, id int64) neo4j.TransactionWork { + return func(tx neo4j.Transaction) (interface{}, error) { + var nodelist []neo4j.Node + query := + ` + WITH apoc.convert.fromJsonMap($stringToAdd) + AS value + UNWIND value.data as d + MERGE (device:Device {id: d.object_id}) + ON CREATE SET device.nativeName = d.object_data.` + "`tapi-object-data`.name[0].value," + ` + device.deviceType = d.object_data.` + "`tapi-object-data`.name[1].value," + ` + device.serialNumber = d.object_data.` + "`tapi-object-data`.name[2].value," + ` + device.softwareVersion = d.object_data.` + "`tapi-object-data`.name[3].value," + ` + device.` + "`operational-state` = d.object_data.`tapi-object-data`.`operational-state`" + ` + WITH device + MATCH (pnd:PND) + WHERE id(pnd) = $pnd + MERGE (device)-[:BELONGS_TO]->(pnd) + RETURN device + ` + + result, err := tx.Run(query, map[string]interface{}{ + "stringToAdd": json, + "pnd": id, + }) + + if err != nil { + 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 + } +} + //StoreNodes 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 Database) StoreNodes(json string) { +func (d Database) StoreNodes(json string) []neo4j.Node { //TODO: remove this after testing and add own gRPC call for it - testPND := PND{name: "test_PND", description: "very, interesting", southboundInterfaces: []string{"TAPI", "RESTCONF"}} - d.StorePND(&testPND) + testPND := PND{name: "test_PND", description: "very interesting", interfaces: []string{"TAPI", "RESTCONF"}} + pnd := d.StorePND(&testPND).Id() + log.Info(pnd) session := createSession(d.driver, true) defer session.Close() - query := - ` - WITH apoc.convert.fromJsonMap($stringToAdd) - AS value - UNWIND value.data as d - MERGE (device:Device {id: d.object_id}) - ON CREATE SET device.nativeName = d.object_data.` + "`tapi-object-data`.name[0].value," + ` - device.deviceType = d.object_data.` + "`tapi-object-data`.name[1].value," + ` - device.serialNumber = d.object_data.` + "`tapi-object-data`.name[2].value," + ` - device.softwareVersion = d.object_data.` + "`tapi-object-data`.name[3].value," + ` - device.` + "`operational-state` = d.object_data.`tapi-object-data`.`operational-state`" + ` - WITH device - MATCH (pnd:PND) - WHERE pnd.name = $pnd - MERGE (device)-[:BELONGS_TO]->(pnd) - ` - - _, err := session.Run( - query, map[string]interface{}{ - "stringToAdd": json, - "pnd": testPND.name, - }) - + result, err := session.WriteTransaction(storeNodesTxFunc(json, pnd)) if err != nil { - log.Info("failed storing Nodes into database:", err) + log.Info(err) } - log.Info("successfully added Nodes into database") + return result.([]neo4j.Node) } //RemoveNodes removes the given nodes and their relationships @@ -144,33 +183,53 @@ func (d Database) RemoveNodes(json string) {} //RemoveSingleNode removes the given node and their relationship by id. func (d Database) RemoveSingleNode(id string) {} +func storeLinksTxFunc(json string) neo4j.TransactionWork { + return func(tx neo4j.Transaction) (interface{}, error) { + var relationsList []neo4j.Relationship + query := + ` + WITH apoc.convert.fromJsonMap($stringToAdd) + AS value + UNWIND value.data as l + MATCH (d:Device), (d2:Device) + WHERE d.id = l.object_data.` + "`tapi-object-data`.`node-edge-point`[0].`node-uuid`" + ` + AND d2.id = l.object_data.` + "`tapi-object-data`.`node-edge-point`[1].`node-uuid`" + ` + CALL apoc.merge.relationship(d,l.object_data.` + "`tapi-object-data`.`layer-qualifier`,{},{}, d2,{})" + ` + YIELD rel + RETURN rel + ` + + result, err := tx.Run(query, map[string]interface{}{ + "stringToAdd": json, + }) + + if err != nil { + 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 + } +} + //StoreLinks stores the links between nodes -func (d Database) StoreLinks(json string) { +func (d Database) StoreLinks(json string) []neo4j.Relationship { session := createSession(d.driver, true) defer session.Close() - query := - ` WITH apoc.convert.fromJsonMap($stringToAdd) - AS value - UNWIND value.data as l - MATCH (d:Device), (d2:Device) - WHERE d.id = l.object_data.` + "`tapi-object-data`.`node-edge-point`[0].`node-uuid`" + ` - AND d2.id = l.object_data.` + "`tapi-object-data`.`node-edge-point`[1].`node-uuid`" + ` - CALL apoc.merge.relationship(d,l.object_data.` + "`tapi-object-data`.`layer-qualifier`,{},{}, d2,{})" + ` - YIELD rel - RETURN rel - ` - - _, err := session.Run( - query, map[string]interface{}{ - "stringToAdd": json, - }) - + result, err := session.WriteTransaction(storeLinksTxFunc(json)) if err != nil { - log.Info("failed storing Links into database:", err) + log.Info(err) } - log.Info("successfully added Links into database") + return result.([]neo4j.Relationship) } //StoreNodeEdgePoints stores the given node edge points (interfaces)