Newer
Older
"encoding/json"
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/interfaces/transport"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
"github.com/docker/docker/pkg/namesgenerator"
"github.com/google/uuid"
"github.com/openconfig/ygot/ygot"
"go.mongodb.org/mongo-driver/bson"
Martin Stiemerling
committed
func NewDevice(name string, uuidInput uuid.UUID, opt *tpb.TransportOption, sbi southbound.SouthboundInterface) (device.Device, error) {
t, err := NewTransport(opt, sbi)
if err != nil {
return nil, err
}
// TODO: this needs to check the case that the uuidInput is set, as the
// same uuid may be already stored.
Martin Stiemerling
committed
if uuidInput == uuid.Nil {
uuidInput = uuid.New()
}
if name == "" {
name = namesgenerator.GetRandomName(0)
}
// We want a representation of the OND's config (the SBI-schema's root created through ygot),
// but do not want to work on the sbi.Schema() directly.
// So the root of sbi.Schema() is never changed when a set or get on a device will be called.
root, err := ygot.DeepCopy(sbi.Schema().Root)
if err != nil {
return nil, err
}
ygotDeepCopy, ok := root.(ygot.GoStruct)
if !ok {
return nil, &errors.ErrInvalidTypeAssertion{
Value: root,
Type: (*ygot.ValidatedGoStruct)(nil),
}
}
return &CsbiDevice{
CommonDevice: CommonDevice{
Martin Stiemerling
committed
UUID: uuidInput,
sbi: sbi,
transport: t,
name: name,
transportOptions: opt,
},
}, nil
}
return &CommonDevice{
Martin Stiemerling
committed
UUID: uuidInput,
sbi: sbi,
transport: t,
name: name,
transportOptions: opt,
// UUID represents the Devices UUID
UUID uuid.UUID
// Device embeds a ygot.GoStruct containing the device details
// SBI is the device's southbound interface implementation
// Transport is the device's Transport implementation
// Name is the device's human readable name
transportOptions *tpb.TransportOption
Manuel Kieweg
committed
}
// ID returns the UUID of the Device
// GetModel returns the ygot representation of the Device
func (d *CommonDevice) GetModel() ygot.GoStruct {
func (d *CommonDevice) Transport() transport.Transport {
func (d *CommonDevice) Name() string {
return d.name
}
func (d *CommonDevice) SBI() southbound.SouthboundInterface {
func (d *CommonDevice) SetTransport(t transport.Transport) {
func (d *CommonDevice) SetName(n string) {
d.name = n
}
func (d *CommonDevice) SetSBI(sbi southbound.SouthboundInterface) {
func (d *CommonDevice) ProcessResponse(resp proto.Message) error {
return d.transport.ProcessResponse(resp, d.Model, d.sbi.Schema())
// IsTransportValid returns a boolean if the transport of a device is valid
func (d *CommonDevice) IsTransportValid() bool {
if d.transportOptions != nil && d.transportOptions.Address != "" {
return true
}
return false
}
// CsbiDevice is used for the cSBI functionality.
type CsbiDevice struct {
CommonDevice
}
// ID returns the UUID of the Device
// GetModel returns the ygot representation of the Device
func (d *CsbiDevice) GetModel() ygot.GoStruct {
// Transport returns the Transport of the device
func (d *CsbiDevice) Transport() transport.Transport {
// Name returns the name of the device
func (d *CsbiDevice) Name() string {
// SBI returns the sbi of the Device
func (d *CsbiDevice) SBI() southbound.SouthboundInterface {
// ProcessResponse processes a response for the Device
func (d *CsbiDevice) ProcessResponse(resp proto.Message) error {
// TODO: callback to send response to caller
return d.transport.ProcessResponse(resp, d.Model, d.sbi.Schema())
// IsTransportValid returns a boolean if the transport of a device is valid
func (d *CsbiDevice) IsTransportValid() bool {
if d.transportOptions != nil && d.transportOptions.Address != "" {
return true
}
return false
}
// MarshalJSON implements the MarshalJSON interface to store a device as JSON
func (d *CommonDevice) MarshalJSON() ([]byte, error) {
var transportType string
var transportAddress string
var transportUsername string
var transportPassword string
// Handling of these cases is necessary as we use partial devices for testing.
// eg. in most tests no transport or sbi is defined.
// The marshaller will crash if we want to access a nil field.
if d.transport == nil || d.transportOptions == nil {
transportType = "testing"
transportAddress = "testing"
transportUsername = "testing"
transportPassword = "testing"
} else {
transportType = d.transport.Type()
transportAddress = d.transportOptions.Address
transportUsername = d.transportOptions.Username
transportPassword = d.transportOptions.Password
}
var sbiUUID uuid.UUID
if d.sbi == nil {
sbiUUID = uuid.UUID{}
} else {
sbiUUID = d.sbi.ID()
}
modelAsString, err := ygot.EmitJSON(d.Model, d.getYgotEmitJSONConfig())
if err != nil {
return []byte{}, err
}
return json.Marshal(&struct {
DeviceID uuid.UUID `json:"id,omitempty"`
Name string `json:"name,omitempty"`
TransportType string `json:"transport_type,omitempty"`
TransportAddress string `json:"transport_address,omitempty"`
TransportUsername string `json:"transport_username,omitempty"`
TransportPassword string `json:"transport_password,omitempty"`
SBI uuid.UUID `json:"sbi,omitempty"`
}{
DeviceID: d.ID(),
Name: d.Name(),
TransportType: transportType,
TransportAddress: transportAddress,
TransportUsername: transportUsername,
TransportPassword: transportPassword,
SBI: sbiUUID,
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
// MarshalBSON implements the MarshalBSON interface to store a device as BSON
func (d *CommonDevice) MarshalBSON() ([]byte, error) {
var transportType string
var transportAddress string
var transportUsername string
var transportPassword string
var transportOptionType spb.Type
// Handling of these cases is necessary as we use partial devices for testing.
// eg. in most tests no transport or sbi is defined.
// The marshaller will crash if we want to access a nil field.
if d.transport == nil || d.transportOptions == nil {
transportType = "testing"
transportAddress = "testing"
transportUsername = "testing"
transportPassword = "testing"
transportOptionType = spb.Type_TYPE_OPENCONFIG
} else {
transportType = d.transport.Type()
transportAddress = d.transportOptions.Address
transportUsername = d.transportOptions.Username
transportPassword = d.transportOptions.Password
transportOptionType = d.transportOptions.Type
}
modelAsString, err := ygot.EmitJSON(d.Model, d.getYgotEmitJSONConfig())
if err != nil {
return []byte{}, err
}
return bson.Marshal(&struct {
DeviceID string `bson:"_id,omitempty"`
Name string `bson:"name,omitempty"`
TransportType string `bson:"transport_type,omitempty"`
TransportAddress string `bson:"transport_address,omitempty"`
TransportUsername string `bson:"transport_username,omitempty"`
TransportPassword string `bson:"transport_password,omitempty"`
TransportOptionType spb.Type `bson:"transport_option"`
SBI string `bson:"sbi,omitempty"`
}{
DeviceID: d.ID().String(),
Name: d.Name(),
TransportType: transportType,
TransportAddress: transportAddress,
TransportUsername: transportUsername,
TransportPassword: transportPassword,
TransportOptionType: transportOptionType,
SBI: d.sbi.ID().String(),
})
}
func (d *CommonDevice) getYgotEmitJSONConfig() *ygot.EmitJSONConfig {
return &ygot.EmitJSONConfig{
Format: ygot.RFC7951,
Indent: "",
SkipValidation: true,
RFC7951Config: &ygot.RFC7951JSONConfig{
AppendModuleName: true,
}}
}