Skip to content
Snippets Groups Projects
configurationmanagement.go 9.54 KiB
Newer Older
  • Learn to ignore specific revisions
  • package server
    
    import (
    	"context"
    	"encoding/json"
    	"time"
    
    	cmpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/configurationmanagement"
    	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/networkdomain"
    	"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/nucleus"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/store"
    	"code.fbi.h-da.de/danet/gosdn/controller/topology"
    	"code.fbi.h-da.de/danet/gosdn/controller/topology/links"
    	"code.fbi.h-da.de/danet/gosdn/controller/topology/nodes"
    	"code.fbi.h-da.de/danet/gosdn/controller/topology/ports"
    
    	"google.golang.org/grpc/codes"
    	"google.golang.org/grpc/status"
    
    	"github.com/bufbuild/protovalidate-go"
    
    	"github.com/google/uuid"
    )
    
    // ConfigurationManagementServer represents  ConfigurationManagementServer...
    type ConfigurationManagementServer struct {
    	cmpb.UnimplementedConfigurationManagementServiceServer
    
    	pndService      networkdomain.Service
    	mneService      networkelement.Service
    
    	topologyService topology.Service
    	nodeService     nodes.Service
    	portService     ports.Service
    
    	protoValidator  *protovalidate.Validator
    
    }
    
    // NewConfigurationManagementServer creates the ConfigurationManagementServer..
    func NewConfigurationManagementServer(
    
    	pndService networkdomain.Service,
    	mneService networkelement.Service,
    
    	topologyService topology.Service,
    	nodeService nodes.Service,
    	portService ports.Service,
    
    	protoValidator *protovalidate.Validator,
    
    ) *ConfigurationManagementServer {
    	return &ConfigurationManagementServer{
    
    		pndService:      pndService,
    		mneService:      mneService,
    
    		topologyService: topologyService,
    		nodeService:     nodeService,
    
    		portService:     portService,
    		pluginService:   pluginService,
    
    		protoValidator:  protoValidator,
    
    }
    
    // sdnConfig is used to parse the sdnConfig into JSON.
    type sdnConfig struct {
    
    	PndID           string                          `json:"pndID"`
    	Nodes           []nodes.Node                    `json:"nodes"`
    	Ports           []ports.Port                    `json:"ports"`
    	Links           []links.Link                    `json:"links"`
    	Plugins         []plugin.LoadedPlugin           `json:"plugins"`
    	NetworkElements []networkelement.NetworkElement `json:"networkelements"`
    
    }
    
    // loadedSDNConfig is used to parse the stringified JSON sdnConfig into objects.
    type loadedSDNConfig struct {
    	PndID           string                                `json:"pndID"`
    	Nodes           []nodes.Node                          `json:"nodes"`
    	Ports           []ports.Port                          `json:"ports"`
    	Links           []links.Link                          `json:"links"`
    
    	Plugins         []plugin.LoadedPlugin                 `json:"plugins"`
    
    	NetworkElements []networkelement.LoadedNetworkElement `json:"networkelements"`
    }
    
    // ExportSDNConfig returns the SDN configuration.
    func (c ConfigurationManagementServer) ExportSDNConfig(ctx context.Context, request *cmpb.ExportSDNConfigRequest) (*cmpb.ExportSDNConfigResponse, error) {
    
    	if err := c.protoValidator.Validate(request); err != nil {
    		return nil, status.Errorf(codes.Aborted, "%v", err)
    	}
    
    
    	var sdnConfig = sdnConfig{}
    
    	sdnConfig.PndID = request.Pid
    
    
    	sdnConfig.NetworkElements, err = c.mneService.GetAll()
    
    	if err != nil {
    		return nil, err
    	}
    
    	sdnConfig.Nodes, err = c.nodeService.GetAll()
    	if err != nil {
    		return nil, err
    	}
    	sdnConfig.Ports, err = c.portService.GetAll()
    	if err != nil {
    		return nil, err
    	}
    	sdnConfig.Links, err = c.topologyService.GetAll()
    	if err != nil {
    		return nil, err
    	}
    
    	jsonSDNConfig, err := json.MarshalIndent(sdnConfig, "", "   ")
    	if err != nil {
    		return nil, err
    	}
    
    	sdnConfigDataString := string(jsonSDNConfig)
    
    	return &cmpb.ExportSDNConfigResponse{
    		Timestamp:     time.Now().UnixNano(),
    		SdnConfigData: sdnConfigDataString,
    
    }
    
    // ImportSDNConfig receives an SDN configuration and imports it.
    func (c ConfigurationManagementServer) ImportSDNConfig(ctx context.Context, request *cmpb.ImportSDNConfigRequest) (*cmpb.ImportSDNConfigResponse, error) {
    
    	if err := c.protoValidator.Validate(request); err != nil {
    		return nil, status.Errorf(codes.Aborted, "%v", err)
    	}
    
    
    	pndUUID := uuid.MustParse(request.Pid)
    	var sdnConfig = loadedSDNConfig{}
    	err := json.Unmarshal([]byte(request.SdnConfigData), &sdnConfig)
    	if err != nil {
    		return nil, err
    	}
    
    
    	err = c.deleteAllElementsFromDatabase()
    
    	if err != nil {
    		return nil, err
    	}
    
    	err = c.createElementsFromSDNConfig(&sdnConfig, pndUUID)
    	if err != nil {
    		return nil, err
    	}
    
    	return &cmpb.ImportSDNConfigResponse{
    		Timestamp: time.Now().UnixNano(),
    
    func (c ConfigurationManagementServer) deleteAllElementsFromDatabase() error {
    	if err := c.deleteNetworkElements(); err != nil {
    
    	if err := c.deletePlugins(); err != nil {
    		return err
    	}
    
    	if err := c.deleteTopology(); err != nil {
    
    		return err
    	}
    
    	return nil
    }
    
    func (c ConfigurationManagementServer) deleteTopology() error {
    	links, err := c.topologyService.GetAll()
    	if err != nil {
    		return err
    	}
    	for _, link := range links {
    		err = c.topologyService.DeleteLink(link)
    		if err != nil {
    			return err
    		}
    	}
    
    	ports, err := c.portService.GetAll()
    	if err != nil {
    		return err
    	}
    	for _, port := range ports {
    		err = c.portService.Delete(port)
    		if err != nil {
    			return err
    		}
    	}
    
    	nodes, err := c.nodeService.GetAll()
    	if err != nil {
    		return err
    	}
    	for _, node := range nodes {
    		err = c.nodeService.Delete(node)
    		if err != nil {
    			return err
    		}
    	}
    
    	return nil
    }
    
    
    func (c ConfigurationManagementServer) deleteNetworkElements() error {
    	networkElements, err := c.mneService.GetAll()
    
    	for _, networkElement := range networkElements {
    
    		err = c.mneService.Delete(networkElement)
    
    	return nil
    }
    
    func (c ConfigurationManagementServer) deletePlugins() error {
    	plugins, err := c.pluginService.GetAll()
    	if err != nil {
    		return err
    	}
    	for _, plugin := range plugins {
    		err = c.pluginService.Delete(plugin)
    
    		if err != nil {
    			return err
    		}
    	}
    
    	return nil
    }
    
    func (c ConfigurationManagementServer) createElementsFromSDNConfig(sdnConfig *loadedSDNConfig, pndUUID uuid.UUID) error {
    
    	if err := c.createTopology(sdnConfig); err != nil {
    
    	if err := c.createNetworkElements(sdnConfig, pndUUID); err != nil {
    
    		return err
    	}
    
    	return nil
    }
    
    func (c ConfigurationManagementServer) createTopology(sdnConfig *loadedSDNConfig) error {
    	for _, inputNode := range sdnConfig.Nodes {
    		node := nodes.Node{
    			ID:   inputNode.ID,
    			Name: inputNode.Name,
    		}
    		_, err := c.nodeService.EnsureExists(node)
    		if err != nil {
    			return err
    		}
    	}
    
    	for _, inputPort := range sdnConfig.Ports {
    		port := ports.Port{
    			ID:            inputPort.ID,
    			Name:          inputPort.Name,
    			Configuration: inputPort.Configuration,
    		}
    		_, err := c.portService.EnsureExists(port)
    		if err != nil {
    			return err
    		}
    	}
    
    	for _, inputPort := range sdnConfig.Links {
    		sourceNode, err := c.nodeService.Get(store.Query{ID: inputPort.SourceNode.ID})
    		if err != nil {
    			return err
    		}
    		targetNode, err := c.nodeService.Get(store.Query{ID: inputPort.TargetNode.ID})
    		if err != nil {
    			return err
    		}
    		sourcePort, err := c.portService.Get(store.Query{ID: inputPort.SourcePort.ID})
    		if err != nil {
    			return err
    		}
    		targetPort, err := c.portService.Get(store.Query{ID: inputPort.TargetPort.ID})
    		if err != nil {
    			return err
    		}
    		link := links.Link{
    			ID:         inputPort.ID,
    			Name:       inputPort.Name,
    			SourceNode: sourceNode,
    			TargetNode: targetNode,
    			SourcePort: sourcePort,
    			TargetPort: targetPort,
    		}
    		err = c.topologyService.AddLink(link)
    		if err != nil {
    			return err
    		}
    	}
    
    	return nil
    }
    
    
    func (c ConfigurationManagementServer) createNetworkElements(sdnConfig *loadedSDNConfig, pndUUID uuid.UUID) error {
    
    	for _, inputNetworkElement := range sdnConfig.NetworkElements {
    		transportOption := tpb.TransportOption{
    			Address:  inputNetworkElement.TransportAddress,
    			Username: inputNetworkElement.TransportUsername,
    			Password: inputNetworkElement.TransportPassword,
    			TransportOption: &tpb.TransportOption_GnmiTransportOption{
    				GnmiTransportOption: &tpb.GnmiTransportOption{},
    			},
    
    			// TODO: change TransportOption - type is not needed; this should
    			// be removed as soon as we remove the csbi device type
    
    			Type: spb.Type_TYPE_OPENCONFIG,
    
    
    		plugin, err := c.pluginService.RequestPlugin(uuid.MustParse(inputNetworkElement.Plugin))
    		if err != nil {
    			return err
    		}
    
    		createdNetworkElement, err := nucleus.NewNetworkElement(
    
    			inputNetworkElement.Name,
    			uuid.MustParse(inputNetworkElement.ID),
    
    			&transportOption,
    			pndUUID,
    			plugin,
    
    			inputNetworkElement.GnmiSubscriptionPaths,
    
    			conflict.Metadata{ResourceVersion: inputNetworkElement.Metadata.ResourceVersion},
    
    		if err := c.mneService.Add(createdNetworkElement); err != nil {
    			return err
    		}
    
    
    		if err := c.pluginService.Add(plugin); err != nil {
    			return err
    		}
    
    
    		err = c.mneService.UpdateModel(createdNetworkElement.ID(), inputNetworkElement.Model)
    
    		networkElement, err := c.mneService.Get(store.Query{ID: uuid.MustParse(inputNetworkElement.ID)})
    
    
    		if err := networkelement.EnsureIntendedConfigurationIsAppliedOnNetworkElement(networkElement); err != nil {
    			return err
    		}