diff --git a/nucleus/device.go b/nucleus/device.go index ed963cd7d3ad254061bbd94c049330615d33882f..23d7f0f0b696b6bb6bfa884be63cc95258fbeeb8 100644 --- a/nucleus/device.go +++ b/nucleus/device.go @@ -31,6 +31,20 @@ func NewDevice(name string, opt *tpb.TransportOption, sbi southbound.SouthboundI }, 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 type CommonDevice struct { // UUID represents the Devices UUID diff --git a/nucleus/device_store.go b/nucleus/device_store.go new file mode 100644 index 0000000000000000000000000000000000000000..c9707913c4337670ea3ac57cbbcced8df8792cf4 --- /dev/null +++ b/nucleus/device_store.go @@ -0,0 +1,257 @@ +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 +} diff --git a/nucleus/principalNetworkDomain.go b/nucleus/principalNetworkDomain.go index e4ea228706149ee0fe9ac6c8be51a661d40d0285..cf51f23d469cc5325858d9ce9f794471daf68012 100644 --- a/nucleus/principalNetworkDomain.go +++ b/nucleus/principalNetworkDomain.go @@ -38,10 +38,18 @@ func NewPND(name, description string, id uuid.UUID, sbi southbound.SouthboundInt errChans: make(map[uuid.UUID]chan error), } - // err := pnd.devices.LoadFromFilesystem() - // if err != nil { - // return nil, err - // } + err := pnd.devices.LoadFromFilesystem() + if err != nil { + 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 { return nil, err diff --git a/nucleus/store.go b/nucleus/store.go index 70f9ac2326f14ad35aee6dd87b8b3feaa8a2bb03..a3db56822c690f6d83db396ee808106e89652c1a 100644 --- a/nucleus/store.go +++ b/nucleus/store.go @@ -4,11 +4,9 @@ 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/networkdomain" "code.fbi.h-da.de/cocsn/gosdn/interfaces/southbound" "code.fbi.h-da.de/cocsn/gosdn/interfaces/store" @@ -45,15 +43,15 @@ func NewSbiStore() *SbiStore { return &SbiStore{store} } -// NewDeviceStore returns a DeviceStore -func NewDeviceStore() *DeviceStore { - store := NewNamedStore("deviceStore") - deviceStore := DeviceStore{store: store, deviceNameToUUIDLookup: make(map[string]uuid.UUID)} +// // NewDeviceStore returns a DeviceStore +// func NewDeviceStore() *DeviceStore { +// // store := NewNamedStore("deviceStore") +// 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 func NewChangeStore(name string) *ChangeStore { @@ -64,13 +62,7 @@ func NewChangeStore(name string) *ChangeStore { type genericStore map[uuid.UUID]store.Storable type myStore struct { name string - store genericStore - storeLock sync.RWMutex -} - -type deviceStore struct { - name string - store map[uuid.UUID]CommonDevice + store map[uuid.UUID]store.Storable storeLock sync.RWMutex } @@ -308,193 +300,210 @@ func FromString(id string) (uuid.UUID, error) { return idAsUUID, nil } -// DeviceStore is used to store Devices -type DeviceStore struct { - store.Store - deviceNameToUUIDLookup map[string]uuid.UUID - store myStore -} +// // DeviceStore is used to store Devices +// type DeviceStore struct { +// deviceNameToUUIDLookup map[string]uuid.UUID +// store deviceStore +// } -// 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 - } - } - } +// type storableDevice struct { +// Name string `json:"name,omitempty"` +// ID uuid.UUID `json:"id,omitempty"` +// } - 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") +// // 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 +// } +// } +// } - 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. -// 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} - } +// return d, nil +// } - _, exists := s.deviceNameToUUIDLookup[name] - if exists { - return &errors.ErrAlreadyExists{Item: name} - } +// // 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)) - s.deviceNameToUUIDLookup[name] = item.ID() +// if s.store.Exists(item.ID()) { +// return &errors.ErrAlreadyExists{Item: item} +// } - s.store.storeLock.Lock() - s.store.store[item.ID()] = item - s.store.storeLock.Unlock() +// _, exists := s.deviceNameToUUIDLookup[name] +// if exists { +// return &errors.ErrAlreadyExists{Item: name} +// } - log.WithFields(log.Fields{ - "type": reflect.TypeOf(item), - "uuid": item.ID(), - }).Debug("storable was added") +// s.deviceNameToUUIDLookup[name] = item.ID() - return nil -} +// s.store.storeLock.Lock() +// s.store.store[item.ID()] = item +// s.store.storeLock.Unlock() -// 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 - } +// log.WithFields(log.Fields{ +// "type": reflect.TypeOf(item), +// "uuid": item.ID(), +// }).Debug("storable was added") - var devicesToPersist []*CommonDevice +// return nil +// } - log.Info(fmt.Printf("Store: %+v\n", s)) - log.Info(fmt.Printf("Storename: %s\n", s.store.name)) +// // 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 +// } - for _, value := range s.store.store { - device, _ := value.(*CommonDevice) +// var devicesToPersist []*CommonDevice - devicesToPersist = append(devicesToPersist, device) - } +// for _, value := range s.store.store { +// device, _ := value.(*CommonDevice) - storeDataAsJSON, err := json.MarshalIndent(devicesToPersist, "", " ") - if err != nil { - return err - } +// devicesToPersist = append(devicesToPersist, device) +// } - 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) - if err != nil { - return err - } - if err != nil { - return err - } +// // log.Info(fmt.Printf("Logging into %s for store %s", fileName, s.store.name)) - log.WithFields(log.Fields{ - "type": reflect.TypeOf(item), - "uuid": item.ID(), - }).Debug("storable was added") - return nil -} +// // log.Debug(fmt.Printf("Devices to persist: %v", devicesToPersist)) -// Delete deletes a device from the device store. -func (s DeviceStore) Delete(id uuid.UUID) error { - if !s.store.Exists(id) { - return &errors.ErrNotFound{ID: id} - } +// err = ioutil.WriteFile(fileName, storeDataAsJSON, 0644) +// if err != nil { +// return err +// } +// if err != nil { +// return err +// } - s.store.storeLock.Lock() - delete(s.store.store, id) - s.store.storeLock.Unlock() +// log.WithFields(log.Fields{ +// "type": reflect.TypeOf(item), +// "uuid": item.ID(), +// }).Debug("storable was added") +// return nil +// } - for key, value := range s.deviceNameToUUIDLookup { - if value == id { - delete(s.deviceNameToUUIDLookup, key) - } - } +// // Delete deletes a device from the device store. +// func (s DeviceStore) Delete(id uuid.UUID) error { +// if !s.store.Exists(id) { +// return &errors.ErrNotFound{ID: id} +// } - log.WithFields(log.Fields{ - "uuid": id, - }).Debug("storable was deleted") +// s.store.storeLock.Lock() +// delete(s.store.store, id) +// 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) { - os.MkdirAll(pathToStore, 0700) - } +// return nil +// } - return nil -} +// func ensureFilesystemStorePathExists() error { -func (s DeviceStore) LoadFromFilesystem() error { - ensureFilesystemStorePathExists() +// pathToStore := "stores/" - 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) - if err != nil { - return err - } +// return nil +// } - var loadedStorables []CommonDevice +// func (s *DeviceStore) LoadFromFilesystem() error { +// ensureFilesystemStorePathExists() - err = json.Unmarshal(dat, &loadedStorables) - if err != nil { - log.Info(err) - return err - } +// fileName := fmt.Sprintf("/home/aps/Code/hda/gosdn/stores/%s.json", s.store.name) - for _, storable := range loadedStorables { - log.Info(fmt.Printf("Storable: %+v\n", storable)) - s.Add(&storable, storable.Name) - } +// dat, err := ioutil.ReadFile(fileName) +// if err != nil { +// return err +// } - return nil -} +// var loadedDevices []CommonDevice -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 -} +// err = json.Unmarshal(dat, &loadedDevices) +// if err != nil { +// return err +// } + +// for _, device := range loadedDevices { +// log.Debug(fmt.Printf("Storable: %+v\n", device.GetName())) +// d := device.(*device.Device) +// s.Add(d, device.GetName()) +// } + +// 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 type ChangeStore struct {