Skip to content
Snippets Groups Projects
http.go 5.66 KiB
Newer Older
  • Learn to ignore specific revisions
  • Manuel Kieweg's avatar
    Manuel Kieweg committed
    package nucleus
    
    import (
    	"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
    
    	"context"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"fmt"
    	"github.com/google/uuid"
    	gpb "github.com/openconfig/gnmi/proto/gnmi"
    	log "github.com/sirupsen/logrus"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"io"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"net/http"
    	"net/url"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    var apiOpmap = map[string]Operation{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"update":  TransportUpdate,
    	"replace": TransportReplace,
    	"delete":  TransportDelete,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    }
    
    
    func stopHttpServer() error {
    	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    	defer cancel()
    	log.Info("shutting down http server")
    	return c.httpServer.Shutdown(ctx)
    }
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    func registerHttpHandler() {
    
    	defer func() {
    		if r := recover(); r != nil {
    			fmt.Println("Recovered in f", r)
    		}
    	}()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	http.HandleFunc("/api", httpHandler)
    
    	http.HandleFunc("/livez", healthCheck)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	http.HandleFunc("/readyz", readynessCheck)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    
    // deprecated
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    func httpAPI() error {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	registerHttpHandler()
    
    	c.httpServer = &http.Server{Addr: ":8080"}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	go func() {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		log.Info(c.httpServer.ListenAndServe())
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	}()
    	return nil
    }
    
    
    func healthCheck(writer http.ResponseWriter, request *http.Request) {
    	writer.WriteHeader(http.StatusOK)
    }
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    func readynessCheck(writer http.ResponseWriter, request *http.Request) {
    	writer.WriteHeader(http.StatusOK)
    }
    
    
    // nolint
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    func httpHandler(writer http.ResponseWriter, request *http.Request) {
    	log.WithFields(log.Fields{
    		"request": request,
    	}).Debug("incoming request")
    
    	query, err := url.ParseQuery(request.URL.RawQuery)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		log.Error(err)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusBadRequest)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		return
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    	id, err := uuid.Parse(query.Get("uuid"))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err != nil {
    
    		if err.Error() != "invalid UUID length: 0" {
    			log.Error(err)
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    	pid, err := uuid.Parse(query.Get("pnd"))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err != nil {
    
    		if err.Error() != "invalid UUID length: 0" {
    			log.Error(err)
    		}
    
    	sid, err := uuid.Parse(query.Get("sbi"))
    	if err != nil {
    
    		if err.Error() != "invalid UUID length: 0" {
    			log.Error(err)
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    
    	var pnd PrincipalNetworkDomain
    	var sbi SouthboundInterface
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if query.Get("q") != "init" && query.Get("q") != "getIDs" {
    
    		pnd, err = c.pndc.get(pid)
    		if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			handleServerError(writer, err)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			return
    
    		}
    		sbic := pnd.GetSBIs()
    		sbi, err = sbic.(*sbiStore).get(sid)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			handleServerError(writer, err)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			return
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	switch q := query.Get("q"); q {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	case "addDevice":
    		d, err := NewDevice(sbi, &GnmiTransportOptions{
    			Config: gnmi.Config{
    				Addr:     query.Get("address"),
    				Password: query.Get("password"),
    				Username: query.Get("username"),
    				Encoding: gpb.Encoding_JSON_IETF,
    			},
    			SetNode:   sbi.SetNode(),
    			Unmarshal: sbi.(*OpenConfig).Unmarshal(),
    			RespChan:  make(chan *gpb.SubscribeResponse),
    		})
    		err = pnd.AddDevice(d)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			writer.WriteHeader(http.StatusInternalServerError)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			log.Error(err)
    			return
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusCreated)
    		fmt.Fprintf(writer, "device added\n")
    
    		fmt.Fprintf(writer, "UUID: %v\n", d.UUID)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	case "request":
    		err = pnd.Request(id, query.Get("path"))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			switch err.(type) {
    			case *ErrNotFound:
    				writer.WriteHeader(http.StatusNotFound)
    			default:
    				writer.WriteHeader(http.StatusInternalServerError)
    			}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			log.Error(err)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			return
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusOK)
    	case "requestAll":
    		err = pnd.RequestAll(query.Get("path"))
    		if err != nil {
    			switch err.(type) {
    			case *ErrNotFound:
    				writer.WriteHeader(http.StatusNotFound)
    			default:
    				writer.WriteHeader(http.StatusInternalServerError)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			log.Error(err)
    			return
    		}
    		writer.WriteHeader(http.StatusOK)
    	case "getDevice":
    		device, err := pnd.MarshalDevice(id)
    		if err != nil {
    			switch err.(type) {
    			case *ErrNotFound:
    				writer.WriteHeader(http.StatusNotFound)
    			default:
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				writer.WriteHeader(http.StatusInternalServerError)
    			}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			log.Error(err)
    			return
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.Header().Set("Content-Type", "application/json")
    		fmt.Fprintf(writer, "%v", device)
    	case "getIDs":
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		pnds := c.pndc.UUIDs()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writeIDs(writer, "PNDs", pnds)
    		writeIDs(writer, "SBIs", c.sbic.UUIDs())
    		for _, id := range pnds {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			p, err := c.pndc.get(id)
    			if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				handleServerError(writer, err)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				return
    			}
    
    			writeIDs(writer, "Devices", p.Devices())
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writeIDs(writer, "PNDs", c.pndc.UUIDs())
    		writeIDs(writer, "SBIs", c.sbic.UUIDs())
    	case "update", "replace":
    		if err := pnd.ChangeOND(id, apiOpmap[q], query.Get("path"), query.Get("value")); err != nil {
    			handleServerError(writer, err)
    			return
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusOK)
    	case "delete":
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		if err := pnd.ChangeOND(id, TransportDelete, query.Get("path")); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			handleServerError(writer, err)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			return
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusOK)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	case "change-list":
    
    		changes := pnd.Committed()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writeIDs(writer, "Tentative changes", changes)
    	case "change-list-pending":
    
    		changes := pnd.Pending()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writeIDs(writer, "Pending changes", changes)
    	case "change-commit":
    		cuid, err := uuid.Parse(query.Get("cuid"))
    		if err != nil {
    			handleServerError(writer, err)
    			return
    		}
    
    		if err := pnd.Commit(cuid); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			handleServerError(writer, err)
    			return
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusAccepted)
    	case "change-confirm":
    		cuid, err := uuid.Parse(query.Get("cuid"))
    		if err != nil {
    			handleServerError(writer, err)
    			return
    		}
    
    		if err := pnd.Confirm(cuid); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			handleServerError(writer, err)
    			return
    		}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		writer.WriteHeader(http.StatusAccepted)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	default:
    		writer.WriteHeader(http.StatusBadRequest)
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    func writeIDs(w io.Writer, typ string, ids []uuid.UUID) {
    	fmt.Fprintf(w, "%v:\n", typ)
    	for i, id := range ids {
    		fmt.Fprintf(w, "%v: %v\n", i+1, id)
    	}
    }
    
    func handleServerError(w http.ResponseWriter, err error) {
    	w.WriteHeader(http.StatusInternalServerError)
    	fmt.Fprintf(w, "error: %v", err)
    	log.Error(err)
    }