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,
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 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
}
// 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
}
// 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)
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// 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()
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"`
}{
ID: n.ID(),
Name: n.Name(),
TransportType: transportType,
TransportAddress: transportAddress,
TransportUsername: transportUsername,
TransportPassword: transportPassword,
TransportOptionType: transportOptionType,
Plugin: pluginUUID,
Model: string(modelAsString),
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
})
}
// 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"`
}{
ID: n.ID().String(),
Name: n.Name(),
TransportType: transportType,
TransportAddress: transportAddress,
TransportUsername: transportUsername,
TransportPassword: transportPassword,
TransportOptionType: transportOptionType,
Plugin: pluginUUID.String(),
Model: modelAsString,
})
}
// 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