-
Fabian Seidl authored
See merge request !363
Fabian Seidl authoredSee merge request !363
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PndAdapter.go 8.81 KiB
package adapter
import (
"context"
"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
"code.fbi.h-da.de/danet/gosdn/controller/api"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
"github.com/google/uuid"
"github.com/openconfig/goyang/pkg/yang"
"golang.org/x/sync/errgroup"
"google.golang.org/protobuf/proto"
)
// PndAdapter is an API adapter to reflect the NetworkDomain
// interface.
type PndAdapter struct {
id uuid.UUID
endpoint string
}
// NewPndAdapter creates a PND Adapter. It requires a valid PND UUID and a reachable
// goSDN endpoint.
func NewPndAdapter(id, endpoint string) (*PndAdapter, error) {
pid, err := uuid.Parse(id)
if err != nil {
return nil, err
}
return &PndAdapter{
id: pid,
endpoint: endpoint,
}, nil
}
// AddSbi adds an SBI to the PND Adapter. Currently not implemented.
func (p *PndAdapter) AddSbi(s southbound.SouthboundInterface) error {
return &errors.ErrNotYetImplemented{}
}
// RemoveSbi removes an SBI from the PND Adapter. Currently not implemented.
func (p *PndAdapter) RemoveSbi(uuid.UUID) error {
return &errors.ErrNotYetImplemented{}
}
// AddDevice adds a new device to the controller. The device name is optional.
// If no name is provided a name will be generated upon device creation.
func (p *PndAdapter) AddDevice(ctx context.Context, name string, opts *tpb.TransportOption, sid uuid.UUID) (*ppb.SetOndListResponse, error) {
resp, err := api.AddDevice(ctx, p.endpoint, name, opts, sid, p.ID())
if err != nil {
return nil, err
}
return resp, nil
}
// GetSbiSchemaTree requests a sbi schema tree.
func (p *PndAdapter) GetSbiSchemaTree(ctx context.Context, sid uuid.UUID) (map[string]*yang.Entry, error) {
resp, err := api.GetSbiSchemaTree(ctx, p.Endpoint(), p.ID(), sid)
if err != nil {
return nil, err
}
return resp, nil
}
// GetDevice requests one or multiple devices belonging to a given
// PrincipalNetworkDomain from the controller.
func (p *PndAdapter) GetDevice(ctx context.Context, identifier string) (*ppb.GetOndResponse, error) {
resp, err := api.GetDevice(ctx, p.endpoint, p.id.String(), identifier)
if err != nil {
return nil, err
}
return resp, nil
}
// GetFlattenedDevices requests all devices belonging to the PrincipalNetworkDomain
// attached to this adapter. The requested devices also contain their config
// information as gNMI notifications.
func (p *PndAdapter) GetFlattenedDevices(ctx context.Context) (*ppb.GetFlattenedOndListResponse, error) {
resp, err := api.GetFlattenedDevices(ctx, p.endpoint, p.id.String())
if err != nil {
return nil, err
}
return resp, nil
}
// RemoveDevice removes a device from the controller.
func (p *PndAdapter) RemoveDevice(ctx context.Context, did uuid.UUID) (*ppb.DeleteOndResponse, error) {
resp, err := api.DeleteDevice(ctx, p.endpoint, p.id.String(), did.String())
if err != nil {
return nil, err
}
return resp, nil
}
// RemovePnd removes a PND from the controller.
func (p *PndAdapter) RemovePnd(ctx context.Context, pid uuid.UUID) (*core.DeletePndResponse, error) {
resp, err := api.DeletePnd(ctx, p.endpoint, pid.String())
if err != nil {
return nil, err
}
return resp, nil
}
// ChangeOND sends an API call to the controller requesting the creation of
// a change from the provided Operation, path and value. The Change is marked
// as Pending and times out after the specified timeout period.
func (p *PndAdapter) ChangeOND(ctx context.Context, duid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) (*ppb.SetPathListResponse, error) {
var v string
if len(value) != 0 {
v = value[0]
}
resp, err := api.ChangeRequest(ctx, p.endpoint, duid.String(), p.id.String(), path, v, operation)
if err != nil {
return nil, err
}
return resp, err
}
// Request sends an API call to the controller requesting the specified path
// for the specified device.
func (p *PndAdapter) Request(ctx context.Context, did uuid.UUID, path string) (*ppb.GetPathResponse, error) {
resp, err := api.GetPath(ctx, p.endpoint, p.id.String(), did.String(), path)
if err != nil {
return nil, err
}
return resp, nil
}
// SubscribeONDPath sends an API call to the controller requesting to subscribe
// to a specific path of a specifc device.
func (p *PndAdapter) SubscribeONDPath(ctx context.Context, did uuid.UUID, slist *ppb.SubscriptionList) (ppb.PndService_SubscribePathClient, error) {
resp, err := api.SubscribePath(ctx, p.endpoint, p.id.String(), did.String(), slist)
if err != nil {
return nil, err
}
return resp, nil
}
// RequestAll sends an API call to the controller requesting the specified path
// for all registered devices. Not yet implemented.
func (p *PndAdapter) RequestAll(ctx context.Context, path string) ([]proto.Message, error) {
resp, err := api.GetFlattenedDevices(ctx, p.Endpoint(), p.ID().String())
if err != nil {
return []proto.Message{}, err
}
reqResult := make([]proto.Message, len(resp.Ond))
g := new(errgroup.Group)
for i, ond := range resp.Ond {
i, ond := i, ond
// TODO: probably the controller should do this; this would result in a
// single request from CLI side.
g.Go(func() error {
resp, err := api.GetPath(ctx, p.endpoint, p.id.String(), ond.GetId(), path)
if err != nil {
return err
}
reqResult[i] = resp
return nil
})
}
if err := g.Wait(); err != nil {
// return the parts that succeeded, aswell as the errors that have been
// encountered
return reqResult, err
}
return reqResult, nil
}
// ContainsDevice sends an API call to the controller checking if a device
// with the given UUID is present. Not implemented, always returns false.
func (p *PndAdapter) ContainsDevice(uuid.UUID) bool {
return false
}
// GetSbi sends an API call to the controller requesting the
// registered SBI with the provided ID.
func (p *PndAdapter) GetSbi(ctx context.Context, sid string) (*ppb.GetSbiResponse, error) {
resp, err := api.GetSbi(ctx, p.endpoint, p.id.String(), sid)
if err != nil {
return nil, err
}
return resp, nil
}
// GetSBIs sends an API call to the controller requesting the
// registered SBIs. Not implemented, always returns nil.
func (p *PndAdapter) GetSBIs(ctx context.Context) (*ppb.GetSbiListResponse, error) {
resp, err := api.GetSBIs(ctx, p.endpoint, p.id.String())
if err != nil {
return nil, err
}
return resp, nil
}
// ID returns the PND Adapter's UUID.
func (p *PndAdapter) ID() uuid.UUID {
return p.id
}
// Endpoint returns the PND Adapter's endpoint.
func (p *PndAdapter) Endpoint() string {
return p.endpoint
}
// PendingChanges sends an API call to the controller requesting
// the UUIDs of all pending changes.
func (p *PndAdapter) PendingChanges(ctx context.Context) ([]*ppb.Change, error) {
resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
if err != nil {
return nil, err
}
return filterChanges(ppb.ChangeState_CHANGE_STATE_PENDING, resp), nil
}
// CommittedChanges sends an API call to the controller requesting
// the UUIDs of all committed changes.
func (p *PndAdapter) CommittedChanges(ctx context.Context) ([]*ppb.Change, error) {
resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
if err != nil {
return nil, err
}
return filterChanges(ppb.ChangeState_CHANGE_STATE_COMMITTED, resp), nil
}
// ConfirmedChanges sends an API call to the controller requesting
// the UUIDs of all confirmed changes.
func (p *PndAdapter) ConfirmedChanges(ctx context.Context) ([]*ppb.Change, error) {
resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
if err != nil {
return nil, err
}
return filterChanges(ppb.ChangeState_CHANGE_STATE_CONFIRMED, resp), nil
}
// GetChange sends an API call to the controller requesting one or more changes
// for the specific PND.
func (p *PndAdapter) GetChange(ctx context.Context, identifier ...string) (*ppb.GetChangeResponse, error) {
resp, err := api.GetChange(ctx, p.endpoint, p.id.String(), identifier...)
if err != nil {
return nil, err
}
return resp, nil
}
// Commit sends an API call to the controller committing the specified change.
func (p *PndAdapter) Commit(ctx context.Context, cuid uuid.UUID) (*ppb.SetChangeListResponse, error) {
resp, err := api.Commit(ctx, p.endpoint, p.id.String(), cuid.String())
if err != nil {
return nil, err
}
return resp, nil
}
// Confirm sends an API call to the controller confirming the specified change.
func (p *PndAdapter) Confirm(ctx context.Context, cuid uuid.UUID) (*ppb.SetChangeListResponse, error) {
resp, err := api.Confirm(ctx, p.endpoint, p.id.String(), cuid.String())
if err != nil {
return nil, err
}
return resp, nil
}
func filterChanges(state ppb.ChangeState, resp *ppb.GetChangeListResponse) []*ppb.Change {
changes := make([]*ppb.Change, 0)
for _, ch := range resp.Change {
if ch.State == state {
changes = append(changes, ch)
}
}
return changes
}