Newer
Older
package nucleus
import (
"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/conflict"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport"
"github.com/docker/docker/pkg/namesgenerator"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"google.golang.org/protobuf/proto"
)
// NewNetworkElement creates a network element.
func NewNetworkElement(
name string,
uuidInput uuid.UUID,
opt *tpb.TransportOption,
pndID uuid.UUID,
plugin plugin.Plugin,
metadata conflict.Metadata) (networkelement.NetworkElement, error) {
t, err := NewTransport(opt, plugin)
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.
if uuidInput == uuid.Nil {
uuidInput = uuid.New()
}
if name == "" {
name = namesgenerator.GetRandomName(0)
}
if opt.Type == spb.Type_TYPE_CONTAINERISED {
return &CsbiNetworkElement{
CommonNetworkElement: CommonNetworkElement{
UUID: uuidInput,
Plugin: plugin,
transport: t,
name: name,
transportOptions: opt,
},
}, nil
}
return &CommonNetworkElement{
UUID: uuidInput,
Plugin: plugin,
transport: t,
name: name,
transportOptions: opt,
}, nil
}
// CommonNetworkElement represents an MNE.
type CommonNetworkElement struct {
// UUID represents the Network Elements UUID
UUID uuid.UUID
// Plugin embeds a gosdn ygot plugin. Allows to work on a devices config
// based its supported YANG models. The code for this is generated through
// ygot.
Plugin plugin.Plugin
// Transport is the network element's Transport implementation
transport transport.Transport
// Name is the network element's human readable name
name string
transportOptions *tpb.TransportOption
Metadata conflict.Metadata
// ID of the PND this network element is associated with.
pndID uuid.UUID
}
// ID returns the UUID of the Network Element.
func (n *CommonNetworkElement) ID() uuid.UUID {
return n.UUID
}
// GetModel returns the ygot representation of the Network Element.
func (n *CommonNetworkElement) GetModel() ([]byte, error) {
return n.Plugin.Model(false)
// GetModelAsFilteredCopy returns the ygot representation of the Network
// Element, but as copy with read-only fields removed.
func (n *CommonNetworkElement) GetModelAsFilteredCopy() ([]byte, error) {
return n.Plugin.Model(true)
}
// Transport returns the Transport of the network element.
func (n *CommonNetworkElement) Transport() transport.Transport {
return n.transport
}
// Transport returns the Transport of the network element.
func (d *CommonNetworkElement) GetPlugin() plugin.Plugin {
return d.Plugin
}
// TransportAddress returns the TransportAddress of the network element.
func (n *CommonNetworkElement) TransportAddress() string {
return n.transportOptions.Address
}
// Name returns the name of the network element.
func (n *CommonNetworkElement) Name() string {
return n.name
}
// SetTransport sets the Network Element's Transport.
func (n *CommonNetworkElement) SetTransport(t transport.Transport) {
n.transport = t
}
// SetName sets the Network Element's name.
func (n *CommonNetworkElement) SetName(name string) {
n.name = name
}
// ProcessResponse processes a response for the Network Element.
func (d *CommonNetworkElement) ProcessResponse(resp proto.Message) error {
return d.transport.ProcessResponse(resp)
}
// IsTransportValid returns a boolean if the transport of a network element is valid.
func (n *CommonNetworkElement) IsTransportValid() bool {
if n.transportOptions != nil && n.transportOptions.Address != "" {
return true
}
return false
}
// GetMetadata returns the metadate of a network element.
func (n *CommonNetworkElement) GetMetadata() conflict.Metadata {
return n.Metadata
}
// PndID returns the ID of the associated PND.
func (n *CommonNetworkElement) PndID() uuid.UUID {
return n.pndID
}
// SetPnd sets the Network Element's PndId.
func (n *CommonNetworkElement) SetPnd(id uuid.UUID) {
n.pndID = id
}
// CsbiNetworkElement is used for the cSBI functionality.
type CsbiNetworkElement struct {
CommonNetworkElement
}
// ID returns the UUID of the Network Element.
func (n *CsbiNetworkElement) ID() uuid.UUID {
return n.UUID
}
// GetModel returns the ygot representation of the Network Element.
func (d *CsbiNetworkElement) GetModel() ([]byte, error) {
return d.Plugin.Model(false)
// GetModelAsFilteredCopy returns the ygot representation of the Network
// Element, but as copy with read-only fields removed.
func (n *CsbiNetworkElement) GetModelAsFilteredCopy() ([]byte, error) {
return n.Plugin.Model(true)
}
// Transport returns the Transport of the network element.
func (n *CsbiNetworkElement) Transport() transport.Transport {
return n.transport
}
// Transport returns the Transport of the device.
func (d *CsbiNetworkElement) GetPlugin() plugin.Plugin {
return d.Plugin
}
// Name returns the name of the network element.
func (n *CsbiNetworkElement) Name() string {
return n.name
}
// GetMetadata returns the metadate of a network element.
func (n *CsbiNetworkElement) GetMetadata() conflict.Metadata {
return n.Metadata
}
// PndID returns the ID of the associated PND.
func (n *CsbiNetworkElement) PndID() uuid.UUID {
return n.pndID
}
// ProcessResponse processes a response for the Network Element.
func (d *CsbiNetworkElement) ProcessResponse(resp proto.Message) error {
// TODO: callback to send response to caller
return d.transport.ProcessResponse(resp)
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// IsTransportValid returns a boolean if the transport of a network element is valid.
func (n *CsbiNetworkElement) IsTransportValid() bool {
if n.transportOptions != nil && n.transportOptions.Address != "" {
return true
}
return false
}
// MarshalJSON implements the MarshalJSON interface to store a network element as JSON.
func (n *CommonNetworkElement) MarshalJSON() ([]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 network elements 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 n.transport == nil || n.transportOptions == nil {
transportType = "testing"
transportAddress = "testing"
transportUsername = "testing"
transportPassword = "testing"
transportOptionType = spb.Type_TYPE_OPENCONFIG
} else {
transportType = n.transport.Type()
transportAddress = n.transportOptions.Address
transportUsername = n.transportOptions.Username
transportPassword = n.transportOptions.Password
transportOptionType = n.transportOptions.Type
}
pluginUUID := n.Plugin.ID()
var pndUUID uuid.UUID
if n.pndID == uuid.Nil {
pndUUID = uuid.UUID{}
} else {
pndUUID = n.pndID
}
modelAsString, err := n.Plugin.Model(false)
if err != nil {
return []byte{}, err
}
return json.Marshal(&struct {
ID 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"`
TransportOptionType spb.Type `json:"transport_option"`
Plugin uuid.UUID `json:"plugin,omitempty"`
Model string `bson:"model,omitempty"`
PndID uuid.UUID `json:"pnd_id,omitempty"`
}{
ID: n.ID(),
Name: n.Name(),
TransportType: transportType,
TransportAddress: transportAddress,
TransportUsername: transportUsername,
TransportPassword: transportPassword,
TransportOptionType: transportOptionType,
Plugin: pluginUUID,
Model: string(modelAsString),
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
})
}
// MarshalBSON implements the MarshalBSON interface to store a network element as BSON.
func (n *CommonNetworkElement) 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 network elements 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 n.transport == nil || n.transportOptions == nil {
transportType = "testing"
transportAddress = "testing"
transportUsername = "testing"
transportPassword = "testing"
transportOptionType = spb.Type_TYPE_OPENCONFIG
} else {
transportType = n.transport.Type()
transportAddress = n.transportOptions.Address
transportUsername = n.transportOptions.Username
transportPassword = n.transportOptions.Password
transportOptionType = n.transportOptions.Type
}
pluginUUID := n.Plugin.ID()
modelAsString, err := n.GetModelAsString()
if err != nil {
return []byte{}, err
}
return bson.Marshal(&struct {
ID 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"`
Plugin string `bson:"plugin,omitempty"`
Model string `bson:"model,omitempty"`
PndID string `bson:"pnd_id,omitempty"`
}{
ID: n.ID().String(),
Name: n.Name(),
TransportType: transportType,
TransportAddress: transportAddress,
TransportUsername: transportUsername,
TransportPassword: transportPassword,
TransportOptionType: transportOptionType,
Plugin: pluginUUID.String(),
Model: modelAsString,
PndID: n.pndID.String(),
})
}
// GetModelAsString returns the YANG model of a network element as string.
func (d *CommonNetworkElement) GetModelAsString() (string, error) {
byteModel, err := d.Plugin.Model(false)
return string(byteModel), err