Skip to content
Snippets Groups Projects
PndAdapter.go 7.51 KiB
Newer Older
  • Learn to ignore specific revisions
  • package adapter
    
    import (
    	"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
    }
    
    // NewAdapter 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(name string, opts *tpb.TransportOption, sid uuid.UUID) (*ppb.SetOndListResponse, error) {
    	resp, err := api.AddDevice(p.endpoint, name, opts, sid, p.ID())
    	if err != nil {
    		return nil, err
    	}
    	return resp, nil
    }
    
    func (p *PndAdapter) GetSbiSchemaTree(sid uuid.UUID) (map[string]*yang.Entry, error) {
    	resp, err := api.GetSbiSchemaTree(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(identifier ...string) ([]*ppb.OrchestratedNetworkingDevice, error) {
    	resp, err := api.GetDevice(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() ([]*ppb.OrchestratedNetworkingDevice, error) {
    	resp, err := api.GetDevices(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(did uuid.UUID) (*ppb.DeleteOndResponse, error) {
    	resp, err := api.DeleteDevice(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(pid uuid.UUID) (*core.DeletePndResponse, error) {
    	resp, err := api.DeletePnd(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(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(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(did uuid.UUID, path string) (proto.Message, error) {
    	resp, err := api.GetPath(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(path string) ([]proto.Message, error) {
    	resp, err := api.GetDevices(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(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(sid ...string) ([]*spb.SouthboundInterface, error) {
    	resp, err := api.GetSbi(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() ([]*spb.SouthboundInterface, error) {
    	resp, err := api.GetSBIs(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() []uuid.UUID {
    	resp, err := api.GetChanges(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() []uuid.UUID {
    	resp, err := api.GetChanges(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(cuid uuid.UUID) error {
    	resp, err := api.Commit(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(cuid uuid.UUID) error {
    	resp, err := api.Confirm(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
    }