mirror of
https://github.com/tim-beatham/smegmesh.git
synced 2025-01-21 21:18:55 +01:00
Developed a rest API
This commit is contained in:
parent
44f119b45c
commit
5f176e731f
17
cmd/api/main.go
Normal file
17
cmd/api/main.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
apiServer, err := api.NewSmegServer()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServer.Run(":8080")
|
||||||
|
}
|
@ -11,4 +11,4 @@ interClusterChance: 0.15
|
|||||||
branchRate: 3
|
branchRate: 3
|
||||||
infectionCount: 3
|
infectionCount: 3
|
||||||
keepAliveTime: 10
|
keepAliveTime: 10
|
||||||
pruneTime: 20
|
pruneTime: 20
|
||||||
|
19
go.mod
19
go.mod
@ -15,14 +15,33 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/jsimonetti/rtnetlink v1.3.5 // indirect
|
github.com/jsimonetti/rtnetlink v1.3.5 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||||
github.com/mdlayher/socket v0.5.0 // indirect
|
github.com/mdlayher/socket v0.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
||||||
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.13.0 // indirect
|
golang.org/x/crypto v0.13.0 // indirect
|
||||||
golang.org/x/net v0.15.0 // indirect
|
golang.org/x/net v0.15.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
|
203
pkg/api/apiserver.go
Normal file
203
pkg/api/apiserver.go
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
ipcRpc "net/rpc"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||||
|
|
||||||
|
type ApiServer interface {
|
||||||
|
GetMeshes(c *gin.Context)
|
||||||
|
Run(addr string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type SmegServer struct {
|
||||||
|
router *gin.Engine
|
||||||
|
client *ipcRpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNode {
|
||||||
|
if meshNode.Routes == nil {
|
||||||
|
meshNode.Routes = make([]string, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SmegNode{
|
||||||
|
WgHost: meshNode.WgHost,
|
||||||
|
WgEndpoint: meshNode.WgEndpoint,
|
||||||
|
Endpoint: meshNode.HostEndpoint,
|
||||||
|
Timestamp: int(meshNode.Timestamp),
|
||||||
|
Description: meshNode.Description,
|
||||||
|
Routes: meshNode.Routes,
|
||||||
|
PublicKey: meshNode.PublicKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func meshToAPIMesh(meshId string, nodes []ctrlserver.MeshNode) SmegMesh {
|
||||||
|
var smegMesh SmegMesh
|
||||||
|
smegMesh.MeshId = meshId
|
||||||
|
smegMesh.Nodes = make(map[string]SmegNode)
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
smegMesh.Nodes[node.WgHost] = *meshNodeToAPIMeshNode(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return smegMesh
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMesh: creates a mesh network
|
||||||
|
func (s *SmegServer) CreateMesh(c *gin.Context) {
|
||||||
|
var createMesh CreateMeshRequest
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&createMesh); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRequest := ipc.NewMeshArgs{
|
||||||
|
IfName: createMesh.IfName,
|
||||||
|
WgPort: createMesh.WgPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply string
|
||||||
|
|
||||||
|
err := s.client.Call("IpcHandler.CreateMesh", &ipcRequest, &reply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, &gin.H{
|
||||||
|
"meshid": reply,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// JoinMesh: joins a mesh network
|
||||||
|
func (s *SmegServer) JoinMesh(c *gin.Context) {
|
||||||
|
var joinMesh JoinMeshRequest
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&joinMesh); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRequest := ipc.JoinMeshArgs{
|
||||||
|
MeshId: joinMesh.MeshId,
|
||||||
|
IpAdress: joinMesh.Bootstrap,
|
||||||
|
IfName: joinMesh.IfName,
|
||||||
|
Port: joinMesh.WgPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply string
|
||||||
|
|
||||||
|
err := s.client.Call("IpcHandler.JoinMesh", &ipcRequest, &reply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, &gin.H{
|
||||||
|
"status": "success",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMesh: given a meshId returns the corresponding mesh
|
||||||
|
// network.
|
||||||
|
func (s *SmegServer) GetMesh(c *gin.Context) {
|
||||||
|
meshidParam := c.Param("meshid")
|
||||||
|
|
||||||
|
var meshid string = meshidParam
|
||||||
|
|
||||||
|
getMeshReply := new(ipc.GetMeshReply)
|
||||||
|
|
||||||
|
err := s.client.Call("IpcHandler.GetMesh", &meshid, &getMeshReply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusNotFound,
|
||||||
|
&gin.H{
|
||||||
|
"error": fmt.Sprintf("could not find mesh %s", meshidParam),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh := meshToAPIMesh(meshidParam, getMeshReply.Nodes)
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, mesh)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SmegServer) GetMeshes(c *gin.Context) {
|
||||||
|
listMeshesReply := new(ipc.ListMeshReply)
|
||||||
|
|
||||||
|
err := s.client.Call("IpcHandler.ListMeshes", "", &listMeshesReply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logging.Log.WriteErrorf(err.Error())
|
||||||
|
c.JSON(http.StatusBadRequest, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
meshes := make([]SmegMesh, 0)
|
||||||
|
|
||||||
|
for _, mesh := range listMeshesReply.Meshes {
|
||||||
|
getMeshReply := new(ipc.GetMeshReply)
|
||||||
|
|
||||||
|
err := s.client.Call("IpcHandler.GetMesh", &mesh, &getMeshReply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logging.Log.WriteErrorf(err.Error())
|
||||||
|
c.JSON(http.StatusBadRequest, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
meshes = append(meshes, meshToAPIMesh(mesh, getMeshReply.Nodes))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, meshes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SmegServer) Run(addr string) error {
|
||||||
|
logging.Log.WriteInfof("Running API server")
|
||||||
|
return s.router.Run(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSmegServer() (ApiServer, error) {
|
||||||
|
client, err := ipcRpc.DialHTTP("unix", SockAddr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
router := gin.Default()
|
||||||
|
|
||||||
|
router.Use(gin.LoggerWithConfig(gin.LoggerConfig{
|
||||||
|
Output: logging.Log.Writer(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
smegServer := &SmegServer{
|
||||||
|
router: router,
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
|
||||||
|
router.GET("/meshes", smegServer.GetMeshes)
|
||||||
|
router.GET("/mesh/:meshid", smegServer.GetMesh)
|
||||||
|
router.POST("/mesh/create", smegServer.CreateMesh)
|
||||||
|
router.POST("/mesh/join", smegServer.JoinMesh)
|
||||||
|
return smegServer, nil
|
||||||
|
}
|
28
pkg/api/types.go
Normal file
28
pkg/api/types.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
type SmegNode struct {
|
||||||
|
WgHost string `json:"wgHost"`
|
||||||
|
WgEndpoint string `json:"wgEndpoint"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
Timestamp int `json:"timestamp"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
PublicKey string `json:"publicKey"`
|
||||||
|
Routes []string `json:"routes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SmegMesh struct {
|
||||||
|
MeshId string `json:"meshid"`
|
||||||
|
Nodes map[string]SmegNode `json:"nodes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateMeshRequest struct {
|
||||||
|
IfName string `json:"ifName" binding:"required"`
|
||||||
|
WgPort int `json:"port" binding:"required,gte=1024,lt=65535"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JoinMeshRequest struct {
|
||||||
|
IfName string `json:"ifName" binding:"required"`
|
||||||
|
WgPort int `json:"port" binding:"required,gte=1024,lt=65535"`
|
||||||
|
Bootstrap string `json:"bootstrap" binding:"required"`
|
||||||
|
MeshId string `json:"meshid" binding:"required"`
|
||||||
|
}
|
@ -17,6 +17,7 @@ type MeshNode struct {
|
|||||||
WgHost string
|
WgHost string
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
Routes []string
|
Routes []string
|
||||||
|
Description string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a WireGuard Mesh
|
// Represents a WireGuard Mesh
|
||||||
|
@ -63,7 +63,7 @@ const SockAddr = "/tmp/wgmesh_ipc.sock"
|
|||||||
|
|
||||||
func RunIpcHandler(server MeshIpc) error {
|
func RunIpcHandler(server MeshIpc) error {
|
||||||
if err := os.RemoveAll(SockAddr); err != nil {
|
if err := os.RemoveAll(SockAddr); err != nil {
|
||||||
return errors.New("Could not find to address")
|
return errors.New("could not find to address")
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc.Register(server)
|
rpc.Register(server)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -15,6 +16,7 @@ type Logger interface {
|
|||||||
WriteInfof(msg string, args ...interface{})
|
WriteInfof(msg string, args ...interface{})
|
||||||
WriteErrorf(msg string, args ...interface{})
|
WriteErrorf(msg string, args ...interface{})
|
||||||
WriteWarnf(msg string, args ...interface{})
|
WriteWarnf(msg string, args ...interface{})
|
||||||
|
Writer() io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogrusLogger struct {
|
type LogrusLogger struct {
|
||||||
@ -33,6 +35,10 @@ func (l *LogrusLogger) WriteWarnf(msg string, args ...interface{}) {
|
|||||||
l.logger.Warnf(msg, args...)
|
l.logger.Warnf(msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *LogrusLogger) Writer() io.Writer {
|
||||||
|
return l.logger.Writer()
|
||||||
|
}
|
||||||
|
|
||||||
func NewLogrusLogger() *LogrusLogger {
|
func NewLogrusLogger() *LogrusLogger {
|
||||||
logger := logrus.New()
|
logger := logrus.New()
|
||||||
logger.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
|
logger.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
|
||||||
|
@ -144,6 +144,7 @@ func (n *IpcHandler) GetMesh(meshId string, reply *ipc.GetMeshReply) error {
|
|||||||
WgHost: node.GetWgHost().String(),
|
WgHost: node.GetWgHost().String(),
|
||||||
Timestamp: node.GetTimeStamp(),
|
Timestamp: node.GetTimeStamp(),
|
||||||
Routes: node.GetRoutes(),
|
Routes: node.GetRoutes(),
|
||||||
|
Description: node.GetDescription(),
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes[i] = node
|
nodes[i] = node
|
||||||
|
Loading…
Reference in New Issue
Block a user