package nucleus import ( "fmt" spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound" tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/device" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" "code.fbi.h-da.de/danet/gosdn/controller/store" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" "github.com/google/uuid" log "github.com/sirupsen/logrus" ) // DatabaseDeviceStore is used to store Devices type DatabaseDeviceStore struct { storeName string sbiStore southbound.SbiStore } // NewDatabaseDeviceStore returns a DeviceStore func NewDatabaseDeviceStore(pndUUID uuid.UUID, sbiStore southbound.SbiStore) device.Store { return &DatabaseDeviceStore{ storeName: fmt.Sprintf("device-store-%s.json", pndUUID.String()), sbiStore: sbiStore, } } // Get takes a Device's UUID or name and returns the Device. func (s *DatabaseDeviceStore) Get(query store.Query) (device.Device, error) { var loadedDevice LoadedDevice client, ctx, cancel := database.GetMongoConnection() defer cancel() defer client.Disconnect(ctx) db := client.Database(database.DatabaseName) collection := db.Collection(s.storeName) result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: query.ID}}) if result == nil { return nil, errors.ErrCouldNotFind{StoreName: pndStoreName} } err := result.Decode(&loadedDevice) if err != nil { db := client.Database(database.DatabaseName) collection := db.Collection(s.storeName) result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: query.Name}}) if result == nil { return nil, errors.ErrCouldNotFind{StoreName: pndStoreName} } err := result.Decode(&loadedDevice) if err != nil { log.Printf("Failed marshalling %v", err) return nil, errors.ErrCouldNotFind{StoreName: pndStoreName} } } sbiForDevice, err := s.sbiStore.Get(store.Query{ID: uuid.MustParse(loadedDevice.SBI)}) if err != nil { return nil, err } d, err := NewDevice( loadedDevice.Name, uuid.MustParse(loadedDevice.DeviceID), &tpb.TransportOption{ Address: loadedDevice.TransportAddress, Username: loadedDevice.TransportUsername, Password: loadedDevice.TransportPassword, TransportOption: &tpb.TransportOption_GnmiTransportOption{ GnmiTransportOption: &tpb.GnmiTransportOption{}, }, Type: spb.Type_TYPE_OPENCONFIG, }, sbiForDevice) if err != nil { return nil, err } return d, nil } // GetAll returns all stored devices. func (s *DatabaseDeviceStore) GetAll() ([]device.Device, error) { var loadedDevices []LoadedDevice var devices []device.Device client, ctx, cancel := database.GetMongoConnection() defer cancel() defer client.Disconnect(ctx) db := client.Database(database.DatabaseName) collection := db.Collection(s.storeName) cursor, err := collection.Find(ctx, bson.D{}) if err != nil { return nil, err } defer cursor.Close(ctx) err = cursor.All(ctx, &loadedDevices) if err != nil { log.Printf("Failed marshalling %v", err) return nil, errors.ErrCouldNotMarshall{StoreName: pndStoreName} } for _, device := range loadedDevices { sbiForDevice, err := s.sbiStore.Get(store.Query{ID: uuid.MustParse(device.SBI)}) d, err := NewDevice( device.Name, uuid.MustParse(device.DeviceID), &tpb.TransportOption{ Address: device.TransportAddress, Username: device.TransportUsername, Password: device.TransportPassword, TransportOption: &tpb.TransportOption_GnmiTransportOption{ GnmiTransportOption: &tpb.GnmiTransportOption{}, }, Type: spb.Type_TYPE_OPENCONFIG, }, sbiForDevice) if err != nil { return nil, err } devices = append(devices, d) } return devices, nil } // Add adds a device to the device store. func (s *DatabaseDeviceStore) Add(deviceToAdd device.Device) error { client, ctx, cancel := database.GetMongoConnection() defer cancel() defer client.Disconnect(ctx) _, err := client.Database(database.DatabaseName). Collection(s.storeName). InsertOne(ctx, deviceToAdd) if err != nil { log.Printf("Could not create Device: %v", err) return errors.ErrCouldNotCreate{StoreName: pndStoreName} } return nil } // Update updates a existing device. func (s *DatabaseDeviceStore) Update(deviceToUpdate device.Device) error { var updatedDevice device.Device client, ctx, cancel := database.GetMongoConnection() defer cancel() defer client.Disconnect(ctx) update := bson.M{ "$set": deviceToUpdate, } 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": deviceToUpdate.ID}, update, &opt). Decode(&updatedDevice) if err != nil { log.Printf("Could not update Device: %v", err) return errors.ErrCouldNotUpdate{StoreName: pndStoreName} } return nil } // Delete deletes a device from the device store. func (s *DatabaseDeviceStore) Delete(deviceToDelete device.Device) error { client, ctx, cancel := database.GetMongoConnection() defer cancel() defer client.Disconnect(ctx) db := client.Database(database.DatabaseName) collection := db.Collection(s.storeName) _, err := collection.DeleteOne(ctx, bson.D{primitive.E{Key: deviceToDelete.ID().String()}}) if err != nil { return err } return nil }