123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- package controller
- import (
- "context"
- "encoding/json"
- "errors"
- // "fmt"
- "net/http"
- "time"
- "github.com/gorilla/mux"
- "github.com/gravitl/netmaker/functions"
- "github.com/gravitl/netmaker/models"
- "github.com/gravitl/netmaker/mongoconn"
- "go.mongodb.org/mongo-driver/bson"
- "go.mongodb.org/mongo-driver/mongo/options"
- // "github.com/skip2/go-qrcode"
- )
- func externalHandlers(r *mux.Router) {
- r.HandleFunc("/api/externals", securityCheck(http.HandlerFunc(getAllExternals))).Methods("GET")
- r.HandleFunc("/api/externals/{network}", securityCheck(http.HandlerFunc(getNetworkExternals))).Methods("GET")
- r.HandleFunc("/api/externals/{network}/{clientid}", securityCheck(http.HandlerFunc(getExternal))).Methods("GET")
- r.HandleFunc("/api/externals/{network}/{clientid}/qr", securityCheck(http.HandlerFunc(getExternal))).Methods("GET")
- r.HandleFunc("/api/externals/{network}/{ingressgateway}", securityCheck(http.HandlerFunc(getExternal))).Methods("GET")
- r.HandleFunc("/api/externals/{network}/{clientid}", securityCheck(http.HandlerFunc(updateExternal))).Methods("PUT")
- r.HandleFunc("/api/externals/{network}/{clientid}", securityCheck(http.HandlerFunc(deleteExternal))).Methods("DELETE")
- r.HandleFunc("/api/externals/{network}", securityCheck(http.HandlerFunc(createExternal))).Methods("POST")
- }
- //Gets all nodes associated with network, including pending nodes
- func getNetworkExternals(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- var nodes []models.External
- var params = mux.Vars(r)
- nodes, err := GetNetworkExternals(params["network"])
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- //Returns all the nodes in JSON format
- w.WriteHeader(http.StatusOK)
- json.NewEncoder(w).Encode(nodes)
- }
- func GetNetworkExternals(network string) ([]models.External, error) {
- var nodes []models.External
- collection := mongoconn.Client.Database("netmaker").Collection("nodes")
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- filter := bson.M{"network": network}
- //Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
- cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
- if err != nil {
- return []models.External{}, err
- }
- defer cancel()
- for cur.Next(context.TODO()) {
- //Using a different model for the ReturnExternal (other than regular node).
- //Either we should do this for ALL structs (so Networks and Keys)
- //OR we should just use the original struct
- //My preference is to make some new return structs
- //TODO: Think about this. Not an immediate concern. Just need to get some consistency eventually
- var node models.External
- err := cur.Decode(&node)
- if err != nil {
- return []models.External{}, err
- }
- // add item our array of nodes
- nodes = append(nodes, node)
- }
- //TODO: Another fatal error we should take care of.
- if err := cur.Err(); err != nil {
- return []models.External{}, err
- }
- return nodes, nil
- }
- //A separate function to get all nodes, not just nodes for a particular network.
- //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
- func getAllExternals(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- nodes, err := functions.GetAllExternals()
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- //Return all the nodes in JSON format
- w.WriteHeader(http.StatusOK)
- json.NewEncoder(w).Encode(nodes)
- }
- //Get an individual node. Nothin fancy here folks.
- func getExternal(w http.ResponseWriter, r *http.Request) {
- // set header.
- w.Header().Set("Content-Type", "application/json")
- var params = mux.Vars(r)
- var node models.Node
- collection := mongoconn.Client.Database("netmaker").Collection("nodes")
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- filter := bson.M{"macaddress": params["macaddress"], "network": params["network"]}
- err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&node)
- defer cancel()
- w.WriteHeader(http.StatusOK)
- json.NewEncoder(w).Encode(node)
- }
- //This one's a doozy
- //To create a node
- //Must have valid key and be unique
- func createExternal(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- var params = mux.Vars(r)
- var errorResponse = models.ErrorResponse{
- Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
- }
- networkName := params["network"]
- //Check if network exists first
- //TODO: This is inefficient. Let's find a better way.
- //Just a few rows down we grab the network anyway
- networkexists, err := functions.NetworkExists(networkName)
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- } else if !networkexists {
- errorResponse = models.ErrorResponse{
- Code: http.StatusNotFound, Message: "W1R3: Network does not exist! ",
- }
- returnErrorResponse(w, r, errorResponse)
- return
- }
- var external models.External
- //get node from body of request
- err = json.NewDecoder(r.Body).Decode(&external)
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- err = ValidateExternalCreate(external)
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "badrequest"))
- return
- }
- node, err = CreateExternal(node, networkName)
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- w.WriteHeader(http.StatusOK)
- json.NewEncoder(w).Encode(node)
- }
- func updateExternal(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- var params = mux.Vars(r)
- //Get id from parameters
- //id, _ := primitive.ObjectIDFromHex(params["id"])
- var node models.External
- //start here
- node, err := functions.GetExternalByMacAddress(params["network"], params["macaddress"])
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- var nodechange models.ExternalUpdate
- // we decode our body request params
- _ = json.NewDecoder(r.Body).Decode(&nodechange)
- if nodechange.Network == "" {
- nodechange.Network = node.Network
- }
- if nodechange.MacAddress == "" {
- nodechange.MacAddress = node.MacAddress
- }
- err = ValidateExternalUpdate(params["network"], nodechange)
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "badrequest"))
- return
- }
- node, err = UpdateExternal(nodechange, node)
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- w.WriteHeader(http.StatusOK)
- json.NewEncoder(w).Encode(node)
- }
- //Delete a node
- //Pretty straightforward
- func deleteExternal(w http.ResponseWriter, r *http.Request) {
- // Set header
- w.Header().Set("Content-Type", "application/json")
- // get params
- var params = mux.Vars(r)
- success, err := DeleteExternal(params["macaddress"], params["network"])
- if err != nil {
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- } else if !success {
- err = errors.New("Could not delete node " + params["macaddress"])
- returnErrorResponse(w, r, formatError(err, "internal"))
- return
- }
- returnSuccessResponse(w, r, params["macaddress"]+" deleted.")
- }
|