working version of the RESTful server with samples

This commit is contained in:
Ryan Zhang
2020-08-11 20:45:02 -07:00
parent 06ed5e4cc1
commit b8ef48f728
8 changed files with 50 additions and 28 deletions

1
.gitignore vendored
View File

@@ -32,3 +32,4 @@ vendor/
.vscode
pkg/test/vela
tmp/

View File

@@ -1,4 +1,4 @@
package server
package main
import (
"context"
@@ -22,7 +22,7 @@ func main() {
var logRetainDate int
var logCompress, development bool
flag.StringVar(&logFilePath, "log-file-path", "", "The address the metric endpoint binds to.")
flag.StringVar(&logFilePath, "log-file-path", "", "The log file path.")
flag.IntVar(&logRetainDate, "log-retain-date", 7, "The number of days of logs history to retain.")
flag.BoolVar(&logCompress, "log-compress", true, "Enable compression on the rotated logs.")
flag.BoolVar(&development, "development", true, "Development mode.")
@@ -43,14 +43,18 @@ func main() {
o.Development = development
o.DestWritter = w
}))
//Setup RESTful server
server := server.ApiServer{}
server.Launch()
// handle signal: SIGTERM(15)
// handle signal: SIGTERM(15), SIGKILL(9)
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGTERM)
signal.Notify(sc, syscall.SIGKILL)
select {
case <-sc:
ctx, _ := context.WithTimeout(context.Background(), time.Minute)
go server.Shutdown(ctx)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
server.Shutdown(ctx)
}
}

1
go.mod
View File

@@ -16,6 +16,7 @@ require (
github.com/spf13/cobra v1.0.0
github.com/stretchr/testify v1.6.1
go.uber.org/zap v1.10.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
gotest.tools v2.2.0+incompatible
helm.sh/helm/v3 v3.2.4

View File

@@ -3,13 +3,13 @@ package apis
import "k8s.io/apimachinery/pkg/runtime"
type Environment struct {
EnvironmentName string `json:"environmentName" binding:"exists,min=1,max=128"`
Namespace string `json:"namespace" binding:"exists,min=1,max=128"`
EnvironmentName string `json:"environmentName" binding:"required,min=1,max=32"`
Namespace string `json:"namespace" binding:"required,min=1,max=32"`
}
type AppConfig struct {
AppConfigName string `json:"appName" binding:"exists,max=256"`
Definition runtime.RawExtension `json:"definition" binding:"exists"`
DefinitionType string `json:"definitionType" binding:"exists,max=256"`
DefinitionName string `json:"definitionName" binding:"exists,max=256"`
AppConfigName string `json:"appName" binding:"required,max=64"`
Definition runtime.RawExtension `json:"definition" binding:"required"`
DefinitionType string `json:"definitionType" binding:"required,max=32"`
DefinitionName string `json:"definitionName" binding:"required,max=64"`
}

View File

@@ -1,6 +1,8 @@
package handler
import (
"net/http"
"github.com/gin-gonic/gin"
ctrl "sigs.k8s.io/controller-runtime"
@@ -12,15 +14,24 @@ import (
func CreateEnv(c *gin.Context) {
var envConfig apis.Environment
if err := c.ShouldBindJSON(&envConfig); err != nil {
util.SetErrorAndAbort(c, util.InvalidArgument, "the create environment request body is invalid")
util.HandleError(c, util.InvalidArgument, "the create environment request body is invalid")
return
}
ctrl.Log.Info("Get Create Repo definition", "namespace", envConfig.Namespace)
ctrl.Log.Info("Get a create environment request", "env", envConfig)
// TODO: implement this
c.Status(http.StatusOK)
}
func GetEnv(c *gin.Context) {
envName := c.Param("envName")
ctrl.Log.Info("Get environment Repo Definition request for", "envName", envName)
ctrl.Log.Info("Get a get environment request", "envName", envName)
// TODO: implement this
c.JSON(http.StatusOK, apis.Environment{
EnvironmentName: envName,
Namespace: "test",
})
}
func ListEnv(c *gin.Context) {

View File

@@ -11,14 +11,15 @@ import (
"github.com/cloud-native-application/rudrx/pkg/server/util"
)
// setup the gin http server handler
func setupRoute() http.Handler {
// create the router
router := gin.New()
loggerConfig := gin.LoggerConfig{
Output: os.Stdout,
Formatter: func(param gin.LogFormatterParams) string {
return fmt.Sprintf("%v | %3d | %13v | %15s | %-7s %s\n%s",
param.TimeStamp.Format("2020/01/02 - 15:04:05"),
return fmt.Sprintf("%v | %3d | %13v | %15s | %-7s %s | %s\n",
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
param.StatusCode,
param.Latency,
param.ClientIP,

View File

@@ -5,6 +5,7 @@ import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
ctrl "sigs.k8s.io/controller-runtime"
)
@@ -30,9 +31,9 @@ type errorDetail struct {
}
var errorDetails = map[Code]errorDetail{
PathNotSupported: {"PathNotSupported", http.StatusNotFound, "'%s' against '%s' is not supported"},
InvalidArgument: {"InvalidArgument", http.StatusBadRequest, "%s"},
UnsupportedMediaType: {"UnsupportedMediaType", http.StatusUnsupportedMediaType, "content type should be 'application/json' or 'application/octet-stream'"},
PathNotSupported: {"PathNotSupported", http.StatusNotFound, "'%s' against '%s' is not supported"},
InvalidArgument: {"InvalidArgument", http.StatusBadRequest, "%s"},
UnsupportedMediaType: {"UnsupportedMediaType", http.StatusUnsupportedMediaType, "content type should be 'application/json' or 'application/octet-stream'"},
}
// ID returns the error ID.
@@ -68,3 +69,13 @@ func ConstructError(ec Code, a ...interface{}) error {
return errors.New(msg)
}
// - use setErrorAndAbort to abort the rest of the handlers, mostly called in middleware
func SetErrorAndAbort(c *gin.Context, code Code, msg ...interface{}) {
// Calling abort so no handlers and middlewares will be executed.
c.AbortWithStatusJSON(code.StatusCode(), gin.H{"error": ConstructError(code, msg...).Error()} )
}
func HandleError(c *gin.Context, code Code, msg ...interface{}) {
c.JSON(code.StatusCode(), gin.H{"error": ConstructError(code, msg...).Error()} )
}

View File

@@ -51,18 +51,10 @@ const (
const contextLoggerKey = "logger"
// - if the call is made in handler *before* middleware.HandleError then abortWithError
// - otherwise use setErrorAndAbort to avoid middleware.HandleError being called twice
func SetErrorAndAbort(c *gin.Context, code Code, msg ...interface{}) {
c.Error(ConstructError(code, msg)).SetType(gin.ErrorTypePublic)
// Calling abort so no handlers and middlewares will be executed.
c.AbortWithStatus(code.StatusCode())
}
//NoRoute is a handler which is invoked when there is no route matches.
func NoRoute() gin.HandlerFunc {
return func(c *gin.Context) {
SetErrorAndAbort(c, PathNotSupported)
SetErrorAndAbort(c, PathNotSupported, c.Request.Method, c.Request.URL.Path)
}
}
@@ -133,3 +125,4 @@ func ValidateHeaders() gin.HandlerFunc {
}
}
}