Newer
Older
package topology
import (
"fmt"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/database"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
query "code.fbi.h-da.de/danet/gosdn/controller/store"
"code.fbi.h-da.de/danet/gosdn/controller/topology/links"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Store defines a Topology store interface
type Store interface {
Add(links.Link) error
Update(links.Link) error
Delete(links.Link) error
Get(query.Query) (links.Link, error)
GetAll() ([]links.Link, error)
}
// DatabaseTopologyStore is a database store for the topology
type DatabaseTopologyStore struct {
storeName string
}
// NewDatabaseTopologyStore returns a TopologyStore
func NewDatabaseTopologyStore() Store {
return &DatabaseTopologyStore{
storeName: fmt.Sprint("topology-store.json"),
}
}
// Get takes a link's UUID or name and returns the link.
func (s *DatabaseTopologyStore) Get(query query.Query) (links.Link, error) {
var loadedTopology links.Link
if query.ID.String() != "" {
loadedTopology, err := s.getByID(query.ID)
if err != nil {
return loadedTopology, errors.ErrCouldNotFind{ID: query.ID, Name: query.Name}
}
return loadedTopology, nil
}
loadedTopology, err := s.getByName(query.Name)
if err != nil {
return loadedTopology, errors.ErrCouldNotFind{ID: query.ID, Name: query.Name}
}
return loadedTopology, nil
}
func (s *DatabaseTopologyStore) getByID(idOfTopology uuid.UUID) (loadedTopology links.Link, err error) {
client, ctx, cancel := database.GetMongoConnection()
defer cancel()
defer func() {
if ferr := client.Disconnect(ctx); ferr != nil {
err = ferr
}
}()
db := client.Database(database.DatabaseName)
collection := db.Collection(s.storeName)
result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: idOfTopology.String()}})
if result == nil {
return loadedTopology, errors.ErrCouldNotFind{ID: idOfTopology}
}
err = result.Decode(&loadedTopology)
if err != nil {
return loadedTopology, errors.ErrCouldNotMarshall{Identifier: idOfTopology, Type: loadedTopology, Err: err}
}
return loadedTopology, nil
}
func (s *DatabaseTopologyStore) getByName(nameOfTopology string) (loadedTopology links.Link, err error) {
client, ctx, cancel := database.GetMongoConnection()
defer cancel()
defer func() {
if ferr := client.Disconnect(ctx); ferr != nil {
err = ferr
}
}()
db := client.Database(database.DatabaseName)
collection := db.Collection(s.storeName)
result := collection.FindOne(ctx, bson.D{primitive.E{Key: "name", Value: nameOfTopology}})
if result == nil {
return loadedTopology, errors.ErrCouldNotFind{Name: nameOfTopology}
}
err = result.Decode(&loadedTopology)
if err != nil {
return loadedTopology, errors.ErrCouldNotMarshall{Identifier: nameOfTopology, Type: loadedTopology, Err: err}
}
return loadedTopology, nil
}
// GetAll returns all stored links.
func (s *DatabaseTopologyStore) GetAll() (loadedTopology []links.Link, err error) {
client, ctx, cancel := database.GetMongoConnection()
defer cancel()
defer func() {
if ferr := client.Disconnect(ctx); ferr != nil {
err = ferr
}
}()
db := client.Database(database.DatabaseName)
collection := db.Collection(s.storeName)
cursor, err := collection.Find(ctx, bson.D{})
if err != nil {
return loadedTopology, err
}
defer func() {
if ferr := cursor.Close(ctx); ferr != nil {
err = ferr
}
}()
err = cursor.All(ctx, &loadedTopology)
if err != nil {
return loadedTopology, errors.ErrCouldNotMarshall{Type: loadedTopology, Err: err}
}
return loadedTopology, nil
}
// Add adds a link to the link store.
func (s *DatabaseTopologyStore) Add(link links.Link) (err error) {
client, ctx, cancel := database.GetMongoConnection()
defer cancel()
defer func() {
if ferr := client.Disconnect(ctx); ferr != nil {
err = ferr
}
}()
_, err = client.Database(database.DatabaseName).
Collection(s.storeName).
InsertOne(ctx, link)
if err != nil {
return errors.ErrCouldNotCreate{Identifier: link.ID, Type: link, Err: err}
}
return nil
}
// Update updates a existing link.
func (s *DatabaseTopologyStore) Update(linkToUpdate links.Link) (err error) {
var updatedLink links.Link
client, ctx, cancel := database.GetMongoConnection()
defer cancel()
defer func() {
if ferr := client.Disconnect(ctx); ferr != nil {
err = ferr
}
}()
update := bson.D{primitive.E{Key: "$set", Value: linkToUpdate}}
upsert := false
after := options.After
opt := options.FindOneAndUpdateOptions{
Upsert: &upsert,
ReturnDocument: &after,
}
err = client.Database(database.DatabaseName).
Collection(s.storeName).
FindOneAndUpdate(
ctx, bson.M{"_id": linkToUpdate.ID.String()}, update, &opt).
Decode(&updatedLink)
if err != nil {
return errors.ErrCouldNotUpdate{Identifier: linkToUpdate.ID, Type: linkToUpdate, Err: err}
}
return nil
}
// Delete deletes a link from the link store.
func (s *DatabaseTopologyStore) Delete(linkToDelete links.Link) (err error) {
client, ctx, cancel := database.GetMongoConnection()
defer cancel()
defer func() {
if ferr := client.Disconnect(ctx); ferr != nil {
err = ferr
}
}()
db := client.Database(database.DatabaseName)
collection := db.Collection(s.storeName)
_, err = collection.DeleteOne(ctx, bson.D{primitive.E{Key: linkToDelete.ID.String()}})
if err != nil {
return err
}
return nil
}