Skip to content
Snippets Groups Projects
PndAdapter.go 7.95 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
    	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
    	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/api"
    	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/change"
    	"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"
    	log "github.com/sirupsen/logrus"
    	"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.OrchestratedNetworkingDevice, error) {
    	resp, err := api.GetDevice(ctx, p.endpoint, p.id.String(), identifier...)
    
    	if err != nil {
    		return nil, err
    	}
    	return resp.Ond, nil
    }
    
    // GetDevices requests all devices belonging to the PrincipalNetworkDomain
    // attached to this adapter.
    
    func (p *PndAdapter) GetDevices(ctx context.Context) ([]*ppb.OrchestratedNetworkingDevice, error) {
    	resp, err := api.GetDevices(ctx, p.endpoint, p.id.String())
    
    	if err != nil {
    		return nil, err
    	}
    	return resp.Ond, 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) (uuid.UUID, 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 uuid.Nil, err
    	}
    	log.Info(resp)
    	return uuid.Nil, 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) (proto.Message, error) {
    	resp, err := api.GetPath(ctx, p.endpoint, p.id.String(), did.String(), path)
    
    	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.GetDevices(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) ([]*spb.SouthboundInterface, error) {
    	resp, err := api.GetSbi(ctx, p.endpoint, p.id.String(), sid...)
    
    	if err != nil {
    		return nil, err
    	}
    	return resp.Sbi, 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) ([]*spb.SouthboundInterface, error) {
    	resp, err := api.GetSBIs(ctx, p.endpoint, p.id.String())
    
    	if err != nil {
    		return nil, err
    	}
    	return resp.Sbi, 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) []uuid.UUID {
    	resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
    
    	if err != nil {
    		log.Error(err)
    		return nil
    	}
    	return filterChanges(ppb.ChangeState_CHANGE_STATE_PENDING, resp)
    }
    
    // CommittedChanges sends an API call to the controller requesting
    // the UUIDs of all committed changes
    
    func (p *PndAdapter) CommittedChanges(ctx context.Context) []uuid.UUID {
    	resp, err := api.GetChanges(ctx, p.endpoint, p.id.String())
    
    	if err != nil {
    		log.Error(err)
    		return nil
    	}
    	return filterChanges(ppb.ChangeState_CHANGE_STATE_COMMITTED, resp)
    }
    
    // GetChange sends an API call to the controller requesting the specified change
    func (p *PndAdapter) GetChange(uuid.UUID) (change.Change, error) {
    	return nil, &errors.ErrNotYetImplemented{}
    }
    
    // Commit sends an API call to the controller committing the specified change
    
    func (p *PndAdapter) Commit(ctx context.Context, cuid uuid.UUID) error {
    	resp, err := api.Commit(ctx, p.endpoint, p.id.String(), cuid.String())
    
    	if err != nil {
    		return err
    	}
    	log.Info(resp)
    	return nil
    }
    
    // Confirm sends an API call to the controller confirming the specified change
    
    func (p *PndAdapter) Confirm(ctx context.Context, cuid uuid.UUID) error {
    	resp, err := api.Confirm(ctx, p.endpoint, p.id.String(), cuid.String())
    
    	if err != nil {
    		return err
    	}
    	log.Info(resp)
    	return nil
    }
    
    func filterChanges(state ppb.ChangeState, resp *ppb.GetChangeListResponse) []uuid.UUID {
    	changes := make([]uuid.UUID, 0)
    	for _, ch := range resp.Change {
    		if ch.State == state {
    			id, _ := uuid.Parse(ch.Id)
    			changes = append(changes, id)
    		}
    	}
    	return changes
    }