Skip to content
Snippets Groups Projects
Commit 822e56dd authored by André Sterba's avatar André Sterba
Browse files

WIP

parent 6adb60ea
Branches
No related tags found
1 merge request!170DRAFT: Persist added devices
...@@ -31,6 +31,20 @@ func NewDevice(name string, opt *tpb.TransportOption, sbi southbound.SouthboundI ...@@ -31,6 +31,20 @@ func NewDevice(name string, opt *tpb.TransportOption, sbi southbound.SouthboundI
}, nil }, nil
} }
func NewDeviceFromStore(uuid uuid.UUID, name string, transport transport.Transport) (device.Device, error) {
if name == "" {
name = namesgenerator.GetRandomName(0)
}
return &CommonDevice{
UUID: uuid,
GoStruct: sbi.Schema().Root,
sbi: sbi,
transport: transport,
Name: name,
}, nil
}
// CommonDevice represents an OND // CommonDevice represents an OND
type CommonDevice struct { type CommonDevice struct {
// UUID represents the Devices UUID // UUID represents the Devices UUID
......
package nucleus
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"reflect"
"sync"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/device"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/store"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/transport"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/errors"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
)
type storableDevice struct {
// UUID represents the Devices UUID
UUID uuid.UUID `json:"uuid"`
// Transport is the device's Transport implementation
Transport transport.Transport `json:"transport"`
// Name is the device's human readable Name
Name string `json:"name"`
// SouthBoundConnectionType to restare a valid Device
SouthBoundConnectionType int32 `json:"south_bound_connection_type"`
}
// type deviceStore struct {
// name string
// store map[uuid.UUID]storableDevice
// storeLock sync.RWMutex
// }
// NewDeviceStore returns a DeviceStore
func NewDeviceStore() *DeviceStore {
// store := NewNamedStore("deviceStore")
deviceStore := DeviceStore{name: "deviceStore", store: make(map[uuid.UUID]store.Storable), storeLock: sync.RWMutex{}, deviceNameToUUIDLookup: make(map[string]uuid.UUID)}
// deviceStore.LoadFromFilesystem()
return &deviceStore
}
// DeviceStore is used to store Devices
type DeviceStore struct {
deviceNameToUUIDLookup map[string]uuid.UUID
name string
store map[uuid.UUID]store.Storable
storeLock sync.RWMutex
}
// type storableDevice struct {
// Name string `json:"name,omitempty"`
// ID uuid.UUID `json:"id,omitempty"`
// }
// GetDevice takes a Device's UUID and returns the Device. If the requested
// Device does not exist an error is returned.
func (s DeviceStore) GetDevice(id uuid.UUID, parseErrors ...error) (device.Device, error) {
var foundID uuid.UUID
foundID = id
for _, parseErrs := range parseErrors {
if parseErrs != nil {
switch e := parseErrs.(type) {
case *errors.ErrInvalidUUID:
myID, ok := s.deviceNameToUUIDLookup[e.DeviceName]
if !ok {
log.Debug(fmt.Sprintf("no device named %s found", foundID))
return nil, &errors.ErrNotFound{}
}
foundID = myID
}
}
}
device, found := s.store[foundID]
if found != true {
return nil, &errors.ErrNotFound{ID: id}
}
d, ok := device.(device.Device)
if !ok {
return nil, &errors.ErrInvalidTypeAssertion{
Value: d,
Type: reflect.TypeOf((device.Device)(nil)),
}
}
log.WithFields(log.Fields{
"uuid": id,
"name": d.GetName(),
}).Debug("device was accessed")
return d, nil
}
// Add adds a device to the device store.
// It also adds the name of the device to the lookup table.
func (s *DeviceStore) Add(item store.Storable, name string) error {
log.Debug(fmt.Sprintf("Adding device with ID %s and name %s", item.ID(), name))
if s.Exists(item.ID()) {
return &errors.ErrAlreadyExists{Item: item}
}
_, exists := s.deviceNameToUUIDLookup[name]
if exists {
return &errors.ErrAlreadyExists{Item: name}
}
s.deviceNameToUUIDLookup[name] = item.ID()
s.storeLock.Lock()
s.store[item.ID()] = item
s.storeLock.Unlock()
log.WithFields(log.Fields{
"type": reflect.TypeOf(item),
"uuid": item.ID(),
}).Debug("storable was added")
return nil
}
// Add adds a Storable to the Store
func (s DeviceStore) AddAndPersist(item Storable, name string) error {
err := s.Add(item, name)
if err != nil {
return err
}
var devicesToPersist []*CommonDevice
for _, value := range s.store {
device, _ := value.(*CommonDevice)
devicesToPersist = append(devicesToPersist, device)
}
storeDataAsJSON, err := json.MarshalIndent(devicesToPersist, "", " ")
if err != nil {
return err
}
fileName := fmt.Sprintf("stores/%s.json", s.name)
// log.Info(fmt.Printf("Logging into %s for store %s", fileName, s.store.name))
// log.Debug(fmt.Printf("Devices to persist: %v", devicesToPersist))
err = ioutil.WriteFile(fileName, storeDataAsJSON, 0644)
if err != nil {
return err
}
if err != nil {
return err
}
log.WithFields(log.Fields{
"type": reflect.TypeOf(item),
"uuid": item.ID(),
}).Debug("storable was added")
return nil
}
// Delete deletes a device from the device store.
func (s DeviceStore) Delete(id uuid.UUID) error {
if !s.Exists(id) {
return &errors.ErrNotFound{ID: id}
}
s.storeLock.Lock()
delete(s.store, id)
s.storeLock.Unlock()
for key, value := range s.deviceNameToUUIDLookup {
if value == id {
delete(s.deviceNameToUUIDLookup, key)
}
}
log.WithFields(log.Fields{
"uuid": id,
}).Debug("storable was deleted")
s.persist()
return nil
}
func ensureFilesystemStorePathExists() error {
pathToStore := "stores/"
if _, err := os.Stat(pathToStore); os.IsNotExist(err) {
os.MkdirAll(pathToStore, 0700)
}
return nil
}
func (s *DeviceStore) LoadFromFilesystem() error {
ensureFilesystemStorePathExists()
fileName := fmt.Sprintf("/home/aps/Code/hda/gosdn/stores/%s.json", s.name)
dat, err := ioutil.ReadFile(fileName)
if err != nil {
return err
}
var loadedDevices []storableDevice
err = json.Unmarshal(dat, &loadedDevices)
if err != nil {
return err
}
for _, loadedDevice := range loadedDevices {
// log.Debug(fmt.Printf("Storable: %+v\n", device.GetName()))
// d := device.(*device.Device)
// s.Add(d, device.GetName())
device, err := NewDevice(loadedDevice.UUID, loadedDevice.Name, loadedDevice.transport, nil)
}
log.Debug(fmt.Printf("Loaded Devices: %v", s.store))
return nil
}
func (s DeviceStore) UUIDs() []uuid.UUID {
s.storeLock.RLock()
defer s.storeLock.RUnlock()
keys := make([]uuid.UUID, len(s.store))
i := 0
for k := range s.store {
keys[i] = k
i++
}
return keys
}
// Exists takes a Storable's UUID and checks its existence in the store.
func (s DeviceStore) Exists(id uuid.UUID) bool {
s.storeLock.RLock()
defer s.storeLock.RUnlock()
_, ok := s.store[id]
return ok
}
...@@ -38,10 +38,18 @@ func NewPND(name, description string, id uuid.UUID, sbi southbound.SouthboundInt ...@@ -38,10 +38,18 @@ func NewPND(name, description string, id uuid.UUID, sbi southbound.SouthboundInt
errChans: make(map[uuid.UUID]chan error), errChans: make(map[uuid.UUID]chan error),
} }
// err := pnd.devices.LoadFromFilesystem() err := pnd.devices.LoadFromFilesystem()
// if err != nil { if err != nil {
// return nil, err log.Info(fmt.Printf("Could not load devices from filesystem, %s", err))
// } }
fmt.Printf("Devices: %+v", pnd.devices.store)
myFancyStore := pnd.devices.store
for k, v := range myFancyStore {
fmt.Printf("Key: %s Device: %+v\n", k, v)
}
if err := pnd.sbic.Add(sbi); err != nil { if err := pnd.sbic.Add(sbi); err != nil {
return nil, err return nil, err
......
...@@ -4,11 +4,9 @@ import ( ...@@ -4,11 +4,9 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"reflect" "reflect"
"sync" "sync"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/device"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/networkdomain" "code.fbi.h-da.de/cocsn/gosdn/interfaces/networkdomain"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/southbound" "code.fbi.h-da.de/cocsn/gosdn/interfaces/southbound"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/store" "code.fbi.h-da.de/cocsn/gosdn/interfaces/store"
...@@ -45,15 +43,15 @@ func NewSbiStore() *SbiStore { ...@@ -45,15 +43,15 @@ func NewSbiStore() *SbiStore {
return &SbiStore{store} return &SbiStore{store}
} }
// NewDeviceStore returns a DeviceStore // // NewDeviceStore returns a DeviceStore
func NewDeviceStore() *DeviceStore { // func NewDeviceStore() *DeviceStore {
store := NewNamedStore("deviceStore") // // store := NewNamedStore("deviceStore")
deviceStore := DeviceStore{store: store, deviceNameToUUIDLookup: make(map[string]uuid.UUID)} // deviceStore := DeviceStore{store: deviceStore{name: "deviceStore", store: make(map[uuid.UUID]storableDevice), storeLock: sync.RWMutex{}}, deviceNameToUUIDLookup: make(map[string]uuid.UUID)}
deviceStore.LoadFromFilesystem() // // deviceStore.LoadFromFilesystem()
return &deviceStore // return &deviceStore
} // }
// NewChangeStore returns a ChangeStore // NewChangeStore returns a ChangeStore
func NewChangeStore(name string) *ChangeStore { func NewChangeStore(name string) *ChangeStore {
...@@ -64,13 +62,7 @@ func NewChangeStore(name string) *ChangeStore { ...@@ -64,13 +62,7 @@ func NewChangeStore(name string) *ChangeStore {
type genericStore map[uuid.UUID]store.Storable type genericStore map[uuid.UUID]store.Storable
type myStore struct { type myStore struct {
name string name string
store genericStore store map[uuid.UUID]store.Storable
storeLock sync.RWMutex
}
type deviceStore struct {
name string
store map[uuid.UUID]CommonDevice
storeLock sync.RWMutex storeLock sync.RWMutex
} }
...@@ -308,193 +300,210 @@ func FromString(id string) (uuid.UUID, error) { ...@@ -308,193 +300,210 @@ func FromString(id string) (uuid.UUID, error) {
return idAsUUID, nil return idAsUUID, nil
} }
// DeviceStore is used to store Devices // // DeviceStore is used to store Devices
type DeviceStore struct { // type DeviceStore struct {
store.Store // deviceNameToUUIDLookup map[string]uuid.UUID
deviceNameToUUIDLookup map[string]uuid.UUID // store deviceStore
store myStore // }
}
// GetDevice takes a Device's UUID and returns the Device. If the requested // type storableDevice struct {
// Device does not exist an error is returned. // Name string `json:"name,omitempty"`
func (s DeviceStore) GetDevice(id uuid.UUID, parseErrors ...error) (device.Device, error) { // ID uuid.UUID `json:"id,omitempty"`
var foundID uuid.UUID // }
foundID = id
for _, parseErrs := range parseErrors {
if parseErrs != nil {
switch e := parseErrs.(type) {
case *errors.ErrInvalidUUID:
myID, ok := s.deviceNameToUUIDLookup[e.DeviceName]
if !ok {
log.Debug(fmt.Sprintf("no device named %s found", foundID))
return nil, &errors.ErrNotFound{}
}
foundID = myID
}
}
}
item, err := s.store.Get(foundID) // // GetDevice takes a Device's UUID and returns the Device. If the requested
if err != nil { // // Device does not exist an error is returned.
return nil, err // func (s DeviceStore) GetDevice(id uuid.UUID, parseErrors ...error) (device.Device, error) {
} // var foundID uuid.UUID
d, ok := item.(device.Device)
if !ok { // foundID = id
return nil, &errors.ErrInvalidTypeAssertion{
Value: d, // for _, parseErrs := range parseErrors {
Type: reflect.TypeOf((device.Device)(nil)), // if parseErrs != nil {
} // switch e := parseErrs.(type) {
} // case *errors.ErrInvalidUUID:
log.WithFields(log.Fields{ // myID, ok := s.deviceNameToUUIDLookup[e.DeviceName]
"uuid": id, // if !ok {
"name": d.GetName(), // log.Debug(fmt.Sprintf("no device named %s found", foundID))
}).Debug("device was accessed") // return nil, &errors.ErrNotFound{}
// }
// foundID = myID
// }
// }
// }
return d, nil // item, err := s.store.Get(foundID)
} // if err != nil {
// return nil, err
// }
// d, ok := item.(device.Device)
// if !ok {
// return nil, &errors.ErrInvalidTypeAssertion{
// Value: d,
// Type: reflect.TypeOf((device.Device)(nil)),
// }
// }
// log.WithFields(log.Fields{
// "uuid": id,
// "name": d.GetName(),
// }).Debug("device was accessed")
// Add adds a device to the device store. // return d, nil
// It also adds the name of the device to the lookup table. // }
func (s DeviceStore) Add(item store.Storable, name string) error {
if s.store.Exists(item.ID()) {
return &errors.ErrAlreadyExists{Item: item}
}
_, exists := s.deviceNameToUUIDLookup[name] // // Add adds a device to the device store.
if exists { // // It also adds the name of the device to the lookup table.
return &errors.ErrAlreadyExists{Item: name} // func (s *DeviceStore) Add(item store.Storable, name string) error {
} // log.Debug(fmt.Sprintf("Adding device with ID %s and name %s", item.ID(), name))
s.deviceNameToUUIDLookup[name] = item.ID() // if s.store.Exists(item.ID()) {
// return &errors.ErrAlreadyExists{Item: item}
// }
s.store.storeLock.Lock() // _, exists := s.deviceNameToUUIDLookup[name]
s.store.store[item.ID()] = item // if exists {
s.store.storeLock.Unlock() // return &errors.ErrAlreadyExists{Item: name}
// }
log.WithFields(log.Fields{ // s.deviceNameToUUIDLookup[name] = item.ID()
"type": reflect.TypeOf(item),
"uuid": item.ID(),
}).Debug("storable was added")
return nil // s.store.storeLock.Lock()
} // s.store.store[item.ID()] = item
// s.store.storeLock.Unlock()
// Add adds a Storable to the Store // log.WithFields(log.Fields{
func (s DeviceStore) AddAndPersist(item Storable, name string) error { // "type": reflect.TypeOf(item),
err := s.Add(item, name) // "uuid": item.ID(),
if err != nil { // }).Debug("storable was added")
return err
}
var devicesToPersist []*CommonDevice // return nil
// }
log.Info(fmt.Printf("Store: %+v\n", s)) // // Add adds a Storable to the Store
log.Info(fmt.Printf("Storename: %s\n", s.store.name)) // func (s DeviceStore) AddAndPersist(item Storable, name string) error {
// err := s.Add(item, name)
// if err != nil {
// return err
// }
for _, value := range s.store.store { // var devicesToPersist []*CommonDevice
device, _ := value.(*CommonDevice)
devicesToPersist = append(devicesToPersist, device) // for _, value := range s.store.store {
} // device, _ := value.(*CommonDevice)
storeDataAsJSON, err := json.MarshalIndent(devicesToPersist, "", " ") // devicesToPersist = append(devicesToPersist, device)
if err != nil { // }
return err
}
fileName := fmt.Sprintf("stores/%s.json", s.store.name) // storeDataAsJSON, err := json.MarshalIndent(devicesToPersist, "", " ")
// if err != nil {
// return err
// }
log.Info(fmt.Printf("Logging into %s for store %s", fileName, s.store.name)) // fileName := fmt.Sprintf("stores/%s.json", s.store.name)
err = ioutil.WriteFile(fileName, storeDataAsJSON, 0644) // // log.Info(fmt.Printf("Logging into %s for store %s", fileName, s.store.name))
if err != nil {
return err
}
if err != nil {
return err
}
log.WithFields(log.Fields{ // // log.Debug(fmt.Printf("Devices to persist: %v", devicesToPersist))
"type": reflect.TypeOf(item),
"uuid": item.ID(),
}).Debug("storable was added")
return nil
}
// Delete deletes a device from the device store. // err = ioutil.WriteFile(fileName, storeDataAsJSON, 0644)
func (s DeviceStore) Delete(id uuid.UUID) error { // if err != nil {
if !s.store.Exists(id) { // return err
return &errors.ErrNotFound{ID: id} // }
} // if err != nil {
// return err
// }
s.store.storeLock.Lock() // log.WithFields(log.Fields{
delete(s.store.store, id) // "type": reflect.TypeOf(item),
s.store.storeLock.Unlock() // "uuid": item.ID(),
// }).Debug("storable was added")
// return nil
// }
for key, value := range s.deviceNameToUUIDLookup { // // Delete deletes a device from the device store.
if value == id { // func (s DeviceStore) Delete(id uuid.UUID) error {
delete(s.deviceNameToUUIDLookup, key) // if !s.store.Exists(id) {
} // return &errors.ErrNotFound{ID: id}
} // }
log.WithFields(log.Fields{ // s.store.storeLock.Lock()
"uuid": id, // delete(s.store.store, id)
}).Debug("storable was deleted") // s.store.storeLock.Unlock()
return nil // for key, value := range s.deviceNameToUUIDLookup {
} // if value == id {
// delete(s.deviceNameToUUIDLookup, key)
// }
// }
func ensureFilesystemStorePathExists() error { // log.WithFields(log.Fields{
// "uuid": id,
// }).Debug("storable was deleted")
pathToStore := "stores/" // s.store.persist()
if _, err := os.Stat(pathToStore); os.IsNotExist(err) { // return nil
os.MkdirAll(pathToStore, 0700) // }
}
return nil // func ensureFilesystemStorePathExists() error {
}
func (s DeviceStore) LoadFromFilesystem() error { // pathToStore := "stores/"
ensureFilesystemStorePathExists()
fileName := fmt.Sprintf("stores/%s.json", s.store.name) // if _, err := os.Stat(pathToStore); os.IsNotExist(err) {
// os.MkdirAll(pathToStore, 0700)
// }
dat, err := ioutil.ReadFile(fileName) // return nil
if err != nil { // }
return err
}
var loadedStorables []CommonDevice // func (s *DeviceStore) LoadFromFilesystem() error {
// ensureFilesystemStorePathExists()
err = json.Unmarshal(dat, &loadedStorables) // fileName := fmt.Sprintf("/home/aps/Code/hda/gosdn/stores/%s.json", s.store.name)
if err != nil {
log.Info(err)
return err
}
for _, storable := range loadedStorables { // dat, err := ioutil.ReadFile(fileName)
log.Info(fmt.Printf("Storable: %+v\n", storable)) // if err != nil {
s.Add(&storable, storable.Name) // return err
} // }
return nil // var loadedDevices []CommonDevice
}
func (s DeviceStore) UUIDs() []uuid.UUID { // err = json.Unmarshal(dat, &loadedDevices)
s.store.storeLock.RLock() // if err != nil {
defer s.store.storeLock.RUnlock() // return err
keys := make([]uuid.UUID, len(s.store.store)) // }
i := 0
for k := range s.store.store { // for _, device := range loadedDevices {
keys[i] = k // log.Debug(fmt.Printf("Storable: %+v\n", device.GetName()))
i++ // d := device.(*device.Device)
} // s.Add(d, device.GetName())
return keys // }
}
// log.Debug(fmt.Printf("Loaded Devices: %v", s.store.store))
// return nil
// }
// func (s DeviceStore) UUIDs() []uuid.UUID {
// s.store.storeLock.RLock()
// defer s.store.storeLock.RUnlock()
// keys := make([]uuid.UUID, len(s.store.store))
// i := 0
// for k := range s.store.store {
// keys[i] = k
// i++
// }
// return keys
// }
// // Exists takes a Storable's UUID and checks its existence in the store.
// func (s DeviceStore) Exists(id uuid.UUID) bool {
// s.store.storeLock.RLock()
// defer s.store.storeLock.RUnlock()
// _, ok := s.store.store[id]
// return ok
// }
// ChangeStore is used to store Changes // ChangeStore is used to store Changes
type ChangeStore struct { type ChangeStore struct {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment