Commit 0d2a1d1f authored by Stefan Dähling's avatar Stefan Dähling
Browse files

use gorilla mux for frontend api server

parent 9cc8168e
Pipeline #415447 passed with stages
in 6 minutes and 34 seconds
......@@ -75,6 +75,10 @@ func (ams *AMS) handleCloneMAP(w http.ResponseWriter, r *http.Request) {
// return info about running clonemap instance
var cmapInfo schemas.CloneMAP
cmapInfo, cmapErr = ams.getCloneMAPInfo()
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, cmapInfo, cmapErr)
return
}
......@@ -86,6 +90,10 @@ func (ams *AMS) handleGetMAS(w http.ResponseWriter, r *http.Request) {
defer ams.logErrors(r.URL.Path, cmapErr, httpErr)
var mass []schemas.MASInfoShort
mass, cmapErr = ams.getMASsShort()
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, mass, cmapErr)
return
}
......@@ -131,6 +139,10 @@ func (ams *AMS) handleGetMASID(w http.ResponseWriter, r *http.Request) {
// return long information about specified MAS
var masInfo schemas.MASInfo
masInfo, cmapErr = ams.getMASInfo(masID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, masInfo, cmapErr)
return
}
......@@ -148,6 +160,10 @@ func (ams *AMS) handleDeleteMASID(w http.ResponseWriter, r *http.Request) {
}
// delete specified MAS
cmapErr = ams.removeMAS(masID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Deleted(w, cmapErr)
return
}
......@@ -162,6 +178,10 @@ func (ams *AMS) handleGetMASName(w http.ResponseWriter, r *http.Request) {
// search for MAS with matching name
var ids []int
ids, cmapErr = ams.getMASByName(name)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, ids, cmapErr)
return
}
......@@ -180,6 +200,10 @@ func (ams *AMS) handleGetAgents(w http.ResponseWriter, r *http.Request) {
// return short information of all agents in specified MAS
var agents schemas.Agents
agents, cmapErr = ams.getAgents(masID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, agents, cmapErr)
return
}
......@@ -209,6 +233,10 @@ func (ams *AMS) handlePostAgent(w http.ResponseWriter, r *http.Request) {
return
}
cmapErr = ams.createAgents(masID, groupSpecs)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Created(w, cmapErr, "text/plain", []byte("Ressource Created"))
return
}
......@@ -226,6 +254,10 @@ func (ams *AMS) handleGetAgentID(w http.ResponseWriter, r *http.Request) {
}
var agentInfo schemas.AgentInfo
agentInfo, cmapErr = ams.getAgentInfo(masID, agentID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, agentInfo, cmapErr)
return
}
......@@ -243,6 +275,10 @@ func (ams *AMS) handleDeleteAgentID(w http.ResponseWriter, r *http.Request) {
}
// delete specified agent
cmapErr = ams.removeAgent(masID, agentID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Deleted(w, cmapErr)
return
}
......@@ -290,6 +326,10 @@ func (ams *AMS) handlePutAgentAddress(w http.ResponseWriter, r *http.Request) {
return
}
cmapErr = ams.updateAgentAddress(masID, agentID, agentAddr)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Updated(w, cmapErr)
return
}
......@@ -314,6 +354,10 @@ func (ams *AMS) handlePutAgentCustom(w http.ResponseWriter, r *http.Request) {
}
custom := string(body)
cmapErr = ams.updateAgentCustom(masID, agentID, custom)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Updated(w, cmapErr)
return
}
......@@ -334,6 +378,10 @@ func (ams *AMS) handleGetAgentName(w http.ResponseWriter, r *http.Request) {
// search for agents with matching name
var ids []int
ids, cmapErr = ams.getAgentsByName(masID, name)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, ids, cmapErr)
return
}
......@@ -352,6 +400,10 @@ func (ams *AMS) handleGetAgencies(w http.ResponseWriter, r *http.Request) {
// return information of specified agency
var agencies schemas.Agencies
agencies, cmapErr = ams.getAgencies(masID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, agencies, cmapErr)
return
}
......@@ -380,6 +432,10 @@ func (ams *AMS) handleGetAgencyID(w http.ResponseWriter, r *http.Request) {
}
var agencySpec schemas.AgencyInfoFull
agencySpec, cmapErr = ams.getAgencyInfoFull(masID, imID, agencyID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, agencySpec, cmapErr)
return
}
......
......@@ -78,6 +78,10 @@ func (df *DF) handleGetMASService(w http.ResponseWriter, r *http.Request) {
}
var svc []schemas.Service
svc, cmapErr = df.stor.searchServices(masID, "")
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, svc, cmapErr)
return
}
......@@ -125,6 +129,10 @@ func (df *DF) handleGetMASGraph(w http.ResponseWriter, r *http.Request) {
}
var gr schemas.Graph
gr, cmapErr = df.stor.getGraph(masID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, gr, cmapErr)
return
}
......@@ -153,6 +161,10 @@ func (df *DF) handlePostMASGraph(w http.ResponseWriter, r *http.Request) {
return
}
cmapErr = df.stor.updateGraph(masID, gr)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Created(w, cmapErr, "text/plain", []byte("Ressource Created"))
return
}
......@@ -171,6 +183,10 @@ func (df *DF) handleGetSvcDesc(w http.ResponseWriter, r *http.Request) {
desc := vars["desc"]
var svc []schemas.Service
svc, cmapErr = df.stor.searchServices(masID, desc)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, svc, cmapErr)
return
}
......@@ -200,6 +216,10 @@ func (df *DF) handleGetSvcNodeDist(w http.ResponseWriter, r *http.Request) {
}
var svc []schemas.Service
svc, cmapErr = df.stor.searchLocalServices(masID, nodeID, dist, desc)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, svc, cmapErr)
return
}
......@@ -218,6 +238,10 @@ func (df *DF) handleGetSvcID(w http.ResponseWriter, r *http.Request) {
svcID := vars["svcid"]
var svc schemas.Service
svc, cmapErr = df.stor.getService(masID, svcID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, svc, cmapErr)
return
}
......@@ -235,6 +259,10 @@ func (df *DF) handleDeleteSvcID(w http.ResponseWriter, r *http.Request) {
}
svcID := vars["svcid"]
cmapErr = df.stor.deregisterService(masID, svcID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Deleted(w, cmapErr)
return
}
......
......@@ -46,152 +46,155 @@ package frontend
import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"strconv"
"git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/common/httpreply"
"git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/schemas"
"github.com/gorilla/mux"
)
// handleAMS handles requests to /api/ams/...
func (fe *Frontend) handleAMS(w http.ResponseWriter, r *http.Request,
respath []string) (resvalid bool, cmapErr error, httpErr error) {
resvalid = false
switch len(respath) {
case 4:
if respath[3] == "mas" {
resvalid = true
cmapErr, httpErr = fe.handleMAS(w, r)
}
case 5:
var masID int
masID, cmapErr = strconv.Atoi(respath[4])
if respath[3] == "mas" && cmapErr == nil {
resvalid = true
cmapErr, httpErr = fe.handlemasID(masID, w, r)
}
case 6:
var masID int
masID, cmapErr = strconv.Atoi(respath[4])
if respath[2] == "clonemap" && respath[3] == "mas" && cmapErr == nil {
if respath[5] == "agents" {
cmapErr, httpErr = fe.handleAgent(masID, w, r)
resvalid = true
}
}
case 7:
var masID int
masID, cmapErr = strconv.Atoi(respath[4])
if respath[2] == "clonemap" && respath[3] == "mas" && cmapErr == nil {
if respath[5] == "agents" {
var agentID int
agentID, cmapErr = strconv.Atoi(respath[6])
if cmapErr == nil {
cmapErr, httpErr = fe.handleAgentID(masID, agentID, w, r)
resvalid = true
}
}
}
default:
cmapErr = errors.New("Resource not found")
// handleGetMASs is the handler for get requests to path /api/ams/mas
func (fe *Frontend) handleGetMASs(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
defer fe.logErrors(r.URL.Path, cmapErr, httpErr)
// return short info of all MAS
var mass []schemas.MASInfoShort
mass, _, cmapErr = fe.amsClient.GetMASsShort()
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, mass, cmapErr)
return
}
// handleMAS is the handler for requests to path /api/ams/mas
func (fe *Frontend) handleMAS(w http.ResponseWriter, r *http.Request) (cmapErr, httpErr error) {
if r.Method == "GET" {
// return short info of all MAS
var mass []schemas.MASInfoShort
mass, _, cmapErr = fe.amsClient.GetMASsShort()
if cmapErr == nil {
httpErr = httpreply.Resource(w, mass, cmapErr)
} else {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
}
} else if r.Method == "POST" {
var body []byte
body, cmapErr = ioutil.ReadAll(r.Body)
if cmapErr == nil {
var masSpec schemas.MASSpec
cmapErr = json.Unmarshal(body, &masSpec)
if cmapErr == nil {
_, httpErr = fe.amsClient.PostMAS(masSpec)
} else {
httpErr = httpreply.JSONUnmarshalError(w)
}
} else {
httpErr = httpreply.InvalidBodyError(w)
}
} else {
httpErr = httpreply.MethodNotAllowed(w)
cmapErr = errors.New("Error: Method not allowed on path /api/ams/mas")
// handlePostMASs is the handler for post requests to path /api/ams/mas
func (fe *Frontend) handlePostMAS(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
defer fe.logErrors(r.URL.Path, cmapErr, httpErr)
var body []byte
body, cmapErr = ioutil.ReadAll(r.Body)
if cmapErr != nil {
httpErr = httpreply.InvalidBodyError(w)
return
}
var masSpec schemas.MASSpec
cmapErr = json.Unmarshal(body, &masSpec)
if cmapErr != nil {
httpErr = httpreply.JSONUnmarshalError(w)
return
}
_, httpErr = fe.amsClient.PostMAS(masSpec)
if httpErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Created(w, cmapErr, "text/plain", []byte("Ressource Created"))
return
}
// handlemasID is the handler for requests to path /api/ams/mas/{mas-id}
func (fe *Frontend) handlemasID(masID int, w http.ResponseWriter, r *http.Request) (cmapErr,
httpErr error) {
if r.Method == "GET" {
// return long information about specified MAS
var masInfo schemas.MASInfo
masInfo, _, cmapErr = fe.amsClient.GetMAS(masID)
httpErr = httpreply.Resource(w, masInfo, cmapErr)
} else if r.Method == "DELETE" {
// delete specified MAS
} else {
httpErr = httpreply.MethodNotAllowed(w)
cmapErr = errors.New("Error: Method not allowed on path /api/ams/mas/{mas-id}")
// handleGetMASID is the handler for get requests to path /api/ams/mas/{masid}
func (fe *Frontend) handleGetMASID(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
defer fe.logErrors(r.URL.Path, cmapErr, httpErr)
vars := mux.Vars(r)
masID, cmapErr := strconv.Atoi(vars["masid"])
if cmapErr != nil {
httpErr = httpreply.NotFoundError(w)
return
}
// return long information about specified MAS
var masInfo schemas.MASInfo
masInfo, _, cmapErr = fe.amsClient.GetMAS(masID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, masInfo, cmapErr)
return
}
// handleDeleteMASID is the handler for delete requests to path /api/ams/mas/{masid}
func (fe *Frontend) handleDeleteMASID(w http.ResponseWriter, r *http.Request) {
return
}
// handleAgent is the handler for requests to path /api/clonemap/mas/{mas-id}/agents
func (fe *Frontend) handleAgent(masID int, w http.ResponseWriter, r *http.Request) (cmapErr,
httpErr error) {
if r.Method == "POST" {
// create new agent in MAS
var body []byte
body, cmapErr = ioutil.ReadAll(r.Body)
if cmapErr == nil {
var groupSpecs []schemas.ImageGroupSpec
cmapErr = json.Unmarshal(body, &groupSpecs)
if cmapErr == nil {
_, cmapErr = fe.amsClient.PostAgents(masID, groupSpecs)
httpErr = httpreply.Created(w, cmapErr, "text/plain", []byte("Ressource Created"))
} else {
httpErr = httpreply.JSONUnmarshalError(w)
}
} else {
httpErr = httpreply.InvalidBodyError(w)
}
} else {
httpErr = httpreply.MethodNotAllowed(w)
cmapErr = errors.New("Error: Method not allowed on path /api/ams/mas/{mas-id}/agents")
// handlePostAgent is the handler for post requests to path /api/clonemap/mas/{masid}/agents
func (fe *Frontend) handlePostAgent(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
defer fe.logErrors(r.URL.Path, cmapErr, httpErr)
vars := mux.Vars(r)
masID, cmapErr := strconv.Atoi(vars["masid"])
if cmapErr != nil {
httpErr = httpreply.NotFoundError(w)
return
}
// create new agent in MAS
var body []byte
body, cmapErr = ioutil.ReadAll(r.Body)
if cmapErr != nil {
httpErr = httpreply.InvalidBodyError(w)
return
}
var groupSpecs []schemas.ImageGroupSpec
cmapErr = json.Unmarshal(body, &groupSpecs)
if cmapErr != nil {
httpErr = httpreply.JSONUnmarshalError(w)
return
}
_, cmapErr = fe.amsClient.PostAgents(masID, groupSpecs)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Created(w, cmapErr, "text/plain", []byte("Ressource Created"))
return
}
// handleAgentID is the handler for requests to path /api/ams/mas/{mas-id}/agents/{agent-id}
func (fe *Frontend) handleAgentID(masID int, agentID int, w http.ResponseWriter,
r *http.Request) (cmapErr, httpErr error) {
if r.Method == "GET" {
// return long information of specified agent
var agentInfo schemas.AgentInfo
agentInfo, _, cmapErr = fe.amsClient.GetAgent(masID, agentID)
httpErr = httpreply.Resource(w, agentInfo, cmapErr)
} else if r.Method == "DELETE" {
// delete specified agent
_, cmapErr = fe.amsClient.DeleteAgent(masID, agentID)
httpErr = httpreply.Deleted(w, cmapErr)
} else {
httpErr = httpreply.MethodNotAllowed(w)
cmapErr = errors.New("Error: Method not allowed on path /api/ams/mas/{mas-id}/agents/" +
"{agent-id}")
// handleGetAgentID is the handler for get requests to path /api/ams/mas/{masid}/agents/{agentid}
func (fe *Frontend) handleGetAgentID(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
defer fe.logErrors(r.URL.Path, cmapErr, httpErr)
masID, agentID, cmapErr := getAgentID(r)
if cmapErr != nil {
httpErr = httpreply.NotFoundError(w)
return
}
// return long information of specified agent
var agentInfo schemas.AgentInfo
agentInfo, _, cmapErr = fe.amsClient.GetAgent(masID, agentID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Resource(w, agentInfo, cmapErr)
return
}
// handleDeleteAgentID is the handler for delete requests to path
// /api/ams/mas/{masid}/agents/{agentid}
func (fe *Frontend) handleDeleteAgentID(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
defer fe.logErrors(r.URL.Path, cmapErr, httpErr)
masID, agentID, cmapErr := getAgentID(r)
if cmapErr != nil {
httpErr = httpreply.NotFoundError(w)
return
}
// delete specified agent
_, cmapErr = fe.amsClient.DeleteAgent(masID, agentID)
if cmapErr != nil {
httpErr = httpreply.CMAPError(w, cmapErr.Error())
return
}
httpErr = httpreply.Deleted(w, cmapErr)
return
}
......@@ -43,21 +43,3 @@ THE SOFTWARE.
*/
package frontend
import (
"errors"
"net/http"
)
// handleDF handles requests to /api/df/...
func (fe *Frontend) handleDF(w http.ResponseWriter, r *http.Request,
respath []string) (resvalid bool, cmapErr error, httpErr error) {
resvalid = false
switch len(respath) {
case 4:
default:
cmapErr = errors.New("Resource not found")
}
return
}
......@@ -45,11 +45,16 @@ THE SOFTWARE.
package frontend
import (
"errors"
"io/ioutil"
"log"
"os"
"time"
amsclient "git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/ams/client"
dfclient "git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/df/client"
logclient "git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/logger/client"
"git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/schemas"
)
// Frontend frontend
......@@ -57,6 +62,8 @@ type Frontend struct {
amsClient *amsclient.Client
dfClient *dfclient.Client
logClient *logclient.Client
logInfo *log.Logger // logger for info logging
logError *log.Logger // logger for error logging
}
// StartFrontend start
......@@ -65,7 +72,35 @@ func StartFrontend() (err error) {
amsClient: amsclient.New(time.Second*60, time.Second*1, 4),
dfClient: dfclient.New(time.Second*60, time.Second*1, 4),
logClient: logclient.New(time.Second*60, time.Second*1, 4),
logError: log.New(os.Stderr, "[ERROR] ", log.LstdFlags),
}
fe.listen()
logType := os.Getenv("CLONEMAP_LOG_LEVEL")
switch logType {
case "info":
fe.logInfo = log.New(os.Stdout, "[INFO] ", log.LstdFlags)
case "error":
fe.logInfo = log.New(ioutil.Discard, "", log.LstdFlags)
default:
err = errors.New("Wrong log type: " + logType)
return
}
fe.logInfo.Println("Starting DF")
serv := fe.server(13000)
if err != nil {
fe.logError.Println(err)
return
}
err = fe.listen(serv)
if err != nil {
fe.logError.Println(err)
}
return
}
// getModuleStatus returns the on/off status of all modules
func (fe *Frontend) getModuleStatus() (mods schemas.ModuleStatus, err error) {
mods.Logging = fe.logClient.Alive()
mods.Core = fe.amsClient.Alive()
mods.DF = fe.dfClient.Alive()
return
}
......@@ -47,69 +47,105 @@ package frontend
import (
"errors"
"net/http"
"strings"
"strconv"
"git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/common/httpreply"
"git.rwth-aachen.de/acs/public/cloud/mas/clonemap/pkg/schemas"
"github.com/gorilla/mux"
)
// handleAPI is the global handler for requests to path /api
func (fe *Frontend) handleAPI(w http.ResponseWriter, r *http.Request) {
// handleGetModules is the handler for get requests to path /api/pf/modules
func (fe *Frontend) handleGetModules(w http.ResponseWriter, r *http.Request) {
fe.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
var cmapErr, httpErr error
// ams.logInfo.Println("Received Request: ", r.Method, " ", r.URL.EscapedPath())
// determine which ressource is requested and call corresponding handler
respath := strings.Split(r.URL.EscapedPath(), "/")
resvalid := false
if len(respath) > 2 {
switch respath[2] {