From b2efd44bd01e42252b9470e1ee4ff84288bf896b Mon Sep 17 00:00:00 2001
From: Malte Bauch <malte.bauch@stud.h-da.de>
Date: Fri, 29 Jan 2021 15:25:14 +0100
Subject: [PATCH] added functionality to load backup.json for pnd

---
 nucleus/cli-handling.go           |  5 +--
 nucleus/controller.go             | 23 ++++++++++--
 nucleus/device.go                 | 40 ++++++++++++++++++---
 nucleus/json_Helper.go            | 59 +++++++++++++++++++++++++++++++
 nucleus/principalNetworkDomain.go |  8 ++---
 5 files changed, 120 insertions(+), 15 deletions(-)
 create mode 100644 nucleus/json_Helper.go

diff --git a/nucleus/cli-handling.go b/nucleus/cli-handling.go
index 08dd67995..d3c2e4bfb 100644
--- a/nucleus/cli-handling.go
+++ b/nucleus/cli-handling.go
@@ -160,9 +160,6 @@ func (s *server) TAPIGetLink(ctx context.Context, in *pb.TAPIRequest) (*pb.TAPIR
 func (s *server) CreatePND(ctx context.Context, in *pb.CreatePNDRequest) (*pb.CreatePNDReply, error) {
 	log.Info("Received: Create a PND with the name", in.GetName())
 	sbi := s.core.southboundInterfaces[in.GetSbi()]
-	if sbi == nil {
-		log.Info("lul")
-	}
 	id := uuid.New()
 	s.core.principalNetworkDomains[id] = NewPND(in.GetName(), in.GetDescription(), sbi)
 	//TODO: export
@@ -226,7 +223,6 @@ func (s *server) AddDevice(ctx context.Context, in *pb.AddDeviceRequest) (*pb.Ad
 	}
 	devicesMap := pnd.GetDevices()
 	devicesMap[newDevice.Uuid] = newDevice
-	//TODO: export
 	s.core.MarshallPNDs()
 
 	return &pb.AddDeviceReply{Message: "Added new Device: " + newDevice.Uuid.String()}, err
@@ -269,5 +265,6 @@ func (s *server) HandleDeviceGetRequest(ctx context.Context, in *pb.DeviceGetReq
 		return &pb.DeviceGetReply{Message: err.Error()}, err
 
 	}
+
 	return &pb.DeviceGetReply{Message: string(d)}, nil
 }
diff --git a/nucleus/controller.go b/nucleus/controller.go
index b04a8fb4e..57742c2a8 100644
--- a/nucleus/controller.go
+++ b/nucleus/controller.go
@@ -7,7 +7,6 @@ import (
 	"os"
 
 	"code.fbi.h-da.de/cocsn/gosdn/database"
-	"github.com/google/uuid"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
 )
@@ -15,7 +14,7 @@ import (
 // Core is the representation of the controllers core
 type Core struct {
 	southboundInterfaces    map[string]SouthboundInterface
-	principalNetworkDomains map[uuid.UUID]PrincipalNetworkDomain
+	principalNetworkDomains PrincipalNetworkDomainMap
 	database                database.Database
 	IsRunning               chan bool
 }
@@ -37,6 +36,11 @@ func (c *Core) Initialize(IsRunningChannel chan bool) {
 	c.AttachDatabase()
 	c.CreateSouthboundInterfaces()
 
+	err = c.UnMarshallPNDs()
+	if err != nil {
+		log.Info(err)
+	}
+
 	c.IsRunning = IsRunningChannel
 }
 
@@ -57,6 +61,21 @@ func (c *Core) MarshallPNDs() error {
 	return nil
 }
 
+func (c *Core) UnMarshallPNDs() error {
+	backup, err := ioutil.ReadFile("./backup.json")
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(backup, &c.principalNetworkDomains)
+	if err != nil {
+		return err
+	}
+	for _, v := range c.principalNetworkDomains {
+		log.Info(v.GetSBIs())
+	}
+	return nil
+}
+
 // CreateSouthboundInterfaces initializes the controller with his SBIs
 func (c *Core) CreateSouthboundInterfaces() {
 	if len(c.southboundInterfaces) == 0 {
diff --git a/nucleus/device.go b/nucleus/device.go
index 868fd68ba..261f56263 100644
--- a/nucleus/device.go
+++ b/nucleus/device.go
@@ -1,13 +1,14 @@
 package nucleus
 
 import (
+	"encoding/json"
 	"github.com/google/uuid"
 	"github.com/openconfig/ygot/ygot"
 )
 
 type Device struct {
 	Uuid      uuid.UUID           `json:"id"`
-	Device    ygot.GoStruct       `json:"device"`
+	Device    ygot.GoStruct       `json:"-"`
 	SBI       SouthboundInterface `json:"sbi"`
 	Config    DeviceConfig        `json:"config"`
 	Transport Transport           `json:"-"`
@@ -16,12 +17,41 @@ type Device struct {
 // Add adds a property to a device. Please
 // use better naming in further develop
 // Also all that Interface Call specific logic belongs to SBI!
-func (d Device) Add(resp interface{}) error {
+func (d *Device) Add(resp interface{}) error {
 	return d.Transport.ProcessResponse(resp, d.Device, d.SBI.Schema())
 }
 
+func (d *Device) UnmarshalJSON(b []byte) error {
+	data := make(map[string]interface{})
+	if err := json.Unmarshal(b, &data); err != nil {
+		return err
+	}
+
+	id, err := uuid.Parse(data["id"].(string))
+	if err != nil {
+		return err
+	}
+	device := Device{
+		Uuid:   id,
+		Device: nil,
+		SBI:    getSouthboundInterfaceFromJSONMap(data["sbi"].(map[string]interface{})),
+		Config: DeviceConfig{
+			Address:  data["config"].(map[string]interface{})["address"].(string),
+			Username: data["config"].(map[string]interface{})["username"].(string),
+			Password: data["config"].(map[string]interface{})["password"].(string),
+		},
+		Transport: nil,
+	}
+	device.SBI.SetDefaults()
+	device.Transport = device.SBI.GetTransport()
+	device.Device = device.SBI.Schema().Root
+
+	*d = device
+	return nil
+}
+
 type DeviceConfig struct {
-	Address  string
-	Username string
-	Password string
+	Address  string `json:"address"`
+	Username string `json:"username"`
+	Password string `json:"password"`
 }
diff --git a/nucleus/json_Helper.go b/nucleus/json_Helper.go
new file mode 100644
index 000000000..f3367cec8
--- /dev/null
+++ b/nucleus/json_Helper.go
@@ -0,0 +1,59 @@
+package nucleus
+
+import (
+	"encoding/json"
+	"github.com/google/uuid"
+)
+
+type PrincipalNetworkDomainMap map[uuid.UUID]PrincipalNetworkDomain
+
+func (m PrincipalNetworkDomainMap) UnmarshalJSON(b []byte) error {
+	data := make(map[string]json.RawMessage)
+	if err := json.Unmarshal(b, &data); err != nil {
+		return err
+	}
+
+	for k, v := range data {
+		dest := &pndImplementation{}
+		if err := json.Unmarshal(v, dest); err != nil {
+			return err
+		}
+		id, err := uuid.Parse(k)
+		if err != nil {
+			return err
+		}
+		m[id] = dest
+	}
+	return nil
+}
+
+type SouthboundInterfaceMap map[string]SouthboundInterface
+
+func (m *SouthboundInterfaceMap) UnmarshalJSON(b []byte) error {
+	m2 := make(map[string]SouthboundInterface)
+	data := make(map[string]interface{})
+	if err := json.Unmarshal(b, &data); err != nil {
+		return err
+	}
+
+	for k, v := range data {
+		m2[k] = getSouthboundInterfaceFromJSONMap(v.(map[string]interface{}))
+	}
+	*m = m2
+	return nil
+}
+
+func getSouthboundInterfaceFromJSONMap(m map[string]interface{}) SouthboundInterface {
+	var newSBI SouthboundInterface
+
+	switch sbi := m["name"]; sbi {
+	case "arista":
+		newSBI = &AristaOC{}
+		newSBI.SetDefaults()
+
+	case "openconfig":
+		newSBI = &OpenConfig{}
+		newSBI.SetDefaults()
+	}
+	return newSBI
+}
diff --git a/nucleus/principalNetworkDomain.go b/nucleus/principalNetworkDomain.go
index 54199758a..66755fe69 100644
--- a/nucleus/principalNetworkDomain.go
+++ b/nucleus/principalNetworkDomain.go
@@ -19,10 +19,10 @@ type PrincipalNetworkDomain interface {
 }
 
 type pndImplementation struct {
-	Name        string                         `json:"name"`
-	Description string                         `json:"description"`
-	Sbi         map[string]SouthboundInterface `json:"sbis"`
-	Devices     map[uuid.UUID]Device           `json:"devices"`
+	Name        string                 `json:"name"`
+	Description string                 `json:"description"`
+	Sbi         SouthboundInterfaceMap `json:"sbis"`
+	Devices     map[uuid.UUID]Device   `json:"devices"`
 }
 
 //NewPND creates a Principle Network Domain
-- 
GitLab