Skip to content
Snippets Groups Projects
mcp.go 7.08 KiB
Newer Older
  • Learn to ignore specific revisions
  • Manuel Kieweg's avatar
    Manuel Kieweg committed
    package ciena
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    import (
    
    	"code.fbi.h-da.de/cocsn/gosdn/database"
    
    	"code.fbi.h-da.de/cocsn/gosdn/nucleus"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	apiclient "code.fbi.h-da.de/cocsn/swagger/apis/mcp/client"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"code.fbi.h-da.de/cocsn/yang-modules/generated/tapi"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"crypto/tls"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"github.com/go-openapi/runtime"
    	httptransport "github.com/go-openapi/runtime/client"
    	"github.com/go-openapi/strfmt"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"github.com/openconfig/ygot/ygot"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	log "github.com/sirupsen/logrus"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"github.com/tidwall/gjson"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"net/http"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    )
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    //Mcp handles requests to a Ciena MCP RESTCONF endpoint
    type Mcp struct {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	transport *httptransport.Runtime
    	client    *apiclient.ServiceTopologyTAPI
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	database  *database.Database
    
    	buffer    *bytes.Buffer
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	config    *nucleus.ClientConfig
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	device    ygot.GoStruct
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    
    // GetConfig returns a ClientConfig struct containing
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    // the current configuration stat of the Ciena SBI ciena
    func (c Mcp) GetConfig() nucleus.ClientConfig {
    
    	return *c.config
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }
    
    
    // ListPorts is a stub to satisfy the interface
    // TODO: Implement
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    func (c Mcp) ListPorts() interface{} {
    
    	return nil
    }
    
    // PushReceiver is a stub to satisfy the interface
    // TODO: Implement
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    func (c Mcp) PushReceiver() error {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    //NewMCPClient creates a Ciena flavores TAPI ciena
    func NewMCPClient(endpoint, username, password string, database *database.Database, config *nucleus.ClientConfig) *Mcp {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	// create the transport
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	transport := httptransport.New(endpoint, "/", nil)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	transport.Transport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	// create the API ciena, with the transport
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	basicAuth := httptransport.BasicAuth(username, password)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	// authenticate ciena
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	transport.DefaultAuthentication = basicAuth
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	client := apiclient.New(transport, strfmt.Default)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    
    	buffer := new(bytes.Buffer)
    
    	transport.Consumers[runtime.JSONMime] = nucleus.YANGConsumer{Data: buffer}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return &Mcp{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		transport: transport,
    		client:    client,
    
    		database:  database,
    		buffer:    buffer,
    
    		config:    config,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		device:    &tapi.Device{},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	}
    }
    
    // GetConnections implements the TAPI Connectivity GetConnections call with a grain of
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    // Ciena salt. The response is written to the ciena's buffer and passed to the database
    func (c *Mcp) GetConnections() error {
    
    	defer c.buffer.Reset()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	_, err := c.client.TapiConnectivityCore.GetTapiCoreContextConnection(nil)
    
    	if err != nil {
    		return err
    	}
    
    	json := preformatJSON(c.buffer.String(), c.config.GjsonConnectionsPath)
    
    	for _, jsonEntry := range json.Array() {
    		dest := &tapi.TapiCommon_Context_ConnectivityContext_Connection{}
    		if err := tapi.Unmarshal([]byte(jsonEntry.String()), dest); err != nil {
    			//TODO: think about a way how to handle this.
    			//logging every error is kinda ugly, since ciena tapi throws a
    			//lot of them.
    			log.Info(err)
    		}
    		log.Info(*dest.Uuid)
    	}
    
    	// c.database.StoreConnections(c.buffer.String())
    	// log.Debug(c.buffer.Next(25))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return err
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }
    
    
    // GetLinks implements the TAPI Topology GetLinks call with a grain of
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    // Ciena salt. The response is written to the ciena's buffer and passed to the database
    func (c *Mcp) GetLinks() error {
    
    	defer c.buffer.Reset()
    	_, err := c.client.TapiTopologyCore.GetTapiCoreContextTopologyMcpBaseTopologyLink(nil)
    
    	if err != nil {
    		return err
    	}
    
    	json := preformatJSON(c.buffer.String(), c.config.GjsonDefaultPath)
    
    	for _, jsonEntry := range json.Array() {
    		dest := &tapi.TapiCommon_Context_TopologyContext_Topology_Link{}
    		if err := tapi.Unmarshal([]byte(jsonEntry.String()), dest); err != nil {
    			//TODO: think about a way how to handle this.
    			//logging every error is kinda ugly, since ciena tapi throws a
    			//lot of them.
    			log.Info(err)
    		}
    		log.Info(*dest.Uuid)
    	}
    
    	// c.database.StoreLinks(c.buffer.String())
    	// log.Debug(c.buffer.Next(25))
    
    // GetNodes implements the TAPI Topology GetNodes call with a grain of
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    // Ciena salt. The response is written to the ciena's buffer and passed to the database
    func (c *Mcp) GetNodes() error {
    
    	defer c.buffer.Reset()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	_, err := c.client.TapiTopologyCore.GetTapiCoreContextTopologyMcpBaseTopologyNode(nil)
    
    	if err != nil {
    		return err
    	}
    
    	json := preformatJSON(c.buffer.String(), c.config.GjsonDefaultPath)
    
    	for _, jsonEntry := range json.Array() {
    		dest := &tapi.TapiCommon_Context_TopologyContext_Topology_Node{}
    		if err := tapi.Unmarshal([]byte(jsonEntry.String()), dest); err != nil {
    			//TODO: think about a way how to handle this.
    			//logging every error is kinda ugly, since ciena tapi throws a
    			//lot of them.
    			log.Info(err)
    		}
    		log.Info(*dest.Uuid)
    	}
    
    	// c.database.StoreNodes(c.buffer.String())
    	// log.Debug(c.buffer.Next(25))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return err
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }
    
    
    // GetNodeEdgePoints implements the TAPI Topology GetNodeEdgePoints call with a grain of
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    // Ciena salt. The response is written to the ciena's buffer and passed to the database
    func (c *Mcp) GetNodeEdgePoints() error {
    
    	defer c.buffer.Reset()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	_, err := c.client.TapiTopologyCore.GetTapiCoreContextTopologyMcpBaseTopologyNodeEdgePoint(nil)
    
    	if err != nil {
    		return err
    	}
    	//TODO: there is no tapi ygot struct that fits the ciena node-edge-point
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	dest := &tapi.TapiCommon_Context_TopologyContext_Topology_Link_NodeEdgePoint{}
    
    	if err := tapi.Unmarshal(c.buffer.Bytes(), dest); err != nil {
    		return err
    	}
    
    	c.database.StoreNodeEdgePoints(c.buffer.String())
    
    	log.Debug(c.buffer.Next(25))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	return err
    
    }
    
    //preformatJSON preformats the recieved JSON for further processing
    func preformatJSON(jsn string, path string) *gjson.Result {
    	//TODO: move this!
    	modifierName := "uppercase"
    	gjson.AddModifier(modifierName, func(jsonString, arg string) string {
    		var jsonMap interface{}
    		err := json.Unmarshal([]byte(jsonString), &jsonMap)
    		if err != nil {
    			log.Info("failed unmarshal for JSON")
    		}
    
    		jsonMap = uppercaseJSONValues(jsonMap)
    		result, err := json.Marshal(jsonMap)
    		if err != nil {
    			log.Info("failed marshal for JSON")
    		}
    		return string(result)
    	})
    
    	formattedJSON := gjson.Get(jsn, path+"|@"+modifierName)
    	return &formattedJSON
    }
    
    //uppercaseJSONValues takes a interface{} created with json.Unmarshal() and changes the containing
    //string values to uppercase
    //returns a interface{} which can be changed back into a JSON string via
    //json.Marshal()
    func uppercaseJSONValues(jsonMap interface{}) interface{} {
    	switch jsonMap := jsonMap.(type) {
    	//check if []interface{} and go through every entry recursively
    	case []interface{}:
    		for i := range jsonMap {
    			jsonMap[i] = uppercaseJSONValues(jsonMap[i])
    		}
    		return jsonMap
    	//check if map[string]interface, handle ciena tapi json specific fixes
    	//and go on recursively
    	case map[string]interface{}:
    		tmpInterfaceMap := make(map[string]interface{}, len(jsonMap))
    		for k, v := range jsonMap {
    			//TODO: maybe we can uppercase them too, but for now:
    			//DO NOT uppercase uuid's
    			if strings.Contains(k, "uuid") {
    				tmpInterfaceMap[k] = v
    			} else {
    				tmpInterfaceMap[k] = uppercaseJSONValues(v)
    			}
    		}
    		return tmpInterfaceMap
    	//ygot: requires enums in uppercase and since CIENA TAPI does sometimes
    	//provide faulty JSON values we need to uppercase them before we process
    	//them further
    	case string:
    		return strings.ToUpper(jsonMap)
    	//default: do nothing (like for bool or other stuff)
    	default:
    		return jsonMap
    	}
    }