mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-18 03:56:36 +00:00
Merge pull request #137 from cloud-native-application/gin-route
RESTful framework
This commit is contained in:
@@ -32,3 +32,4 @@ vendor/
|
||||
.vscode
|
||||
|
||||
pkg/test/vela
|
||||
tmp/
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var logFilePath string
|
||||
var logRetainDate int
|
||||
var logCompress, development bool
|
||||
|
||||
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.")
|
||||
flag.Parse()
|
||||
|
||||
// setup logging
|
||||
var w io.Writer
|
||||
if len(logFilePath) > 0 {
|
||||
w = zapcore.AddSync(&lumberjack.Logger{
|
||||
Filename: logFilePath,
|
||||
MaxAge: logRetainDate, // days
|
||||
Compress: logCompress,
|
||||
})
|
||||
} else {
|
||||
w = os.Stdout
|
||||
}
|
||||
ctrl.SetLogger(zap.New(func(o *zap.Options) {
|
||||
o.Development = development
|
||||
o.DestWritter = w
|
||||
}))
|
||||
|
||||
//Setup RESTful server
|
||||
server := server.ApiServer{}
|
||||
server.Launch()
|
||||
// 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, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
server.Shutdown(ctx)
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
command := newCommand()
|
||||
|
||||
logs.InitLogs()
|
||||
defer logs.FlushLogs()
|
||||
|
||||
|
||||
@@ -313,11 +313,13 @@ type definitionName struct {
|
||||
## Repo related API
|
||||
These API operate on definition files stored in a git repo. It could be a git repo on the local file system.
|
||||
|
||||
The only valid `categoryName` are `workload`,`trait` and `scope`
|
||||
|
||||
They all have a `repoURL` query parameter that stores the git repo's URL so that the server is stateless.
|
||||
|
||||
### Update
|
||||
|
||||
**URL** : `/api/category/${definitionType}/${definitionName}`
|
||||
**URL** : `/api/category/${categoryName}/${definitionName}`
|
||||
|
||||
**Method** : `PUT`
|
||||
|
||||
@@ -336,7 +338,7 @@ type oamDefinition struct {
|
||||
|
||||
### GET
|
||||
|
||||
**URL** : `/api/category/${definitionType}/${definitionName}`
|
||||
**URL** : `/api/category/${categoryName}/${definitionName}`
|
||||
|
||||
**Method** : `Get`
|
||||
|
||||
@@ -353,7 +355,7 @@ type definition struct {
|
||||
|
||||
### List
|
||||
|
||||
**URL** : `/api/category/${definitionType}`
|
||||
**URL** : `/api/category/${categoryName}`
|
||||
|
||||
**Method** : `Get`
|
||||
|
||||
|
||||
@@ -7,13 +7,16 @@ require (
|
||||
github.com/crossplane/crossplane-runtime v0.8.0
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.0.8
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
github.com/onsi/ginkgo v1.11.0
|
||||
github.com/onsi/gomega v1.8.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
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
|
||||
@@ -23,7 +26,7 @@ require (
|
||||
k8s.io/cli-runtime v0.18.6
|
||||
k8s.io/client-go v0.18.6
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kubectl v0.18.6
|
||||
k8s.io/kubectl v0.18.6 // indirect
|
||||
rsc.io/letsencrypt v0.0.3 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.6.0
|
||||
)
|
||||
|
||||
@@ -209,6 +209,10 @@ github.com/gertd/go-pluralize v0.1.7/go.mod h1:O4eNeeIf91MHh1GJ2I47DNtaesm66NYvj
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -269,6 +273,14 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
@@ -308,6 +320,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
|
||||
github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
|
||||
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
||||
@@ -397,6 +411,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
@@ -419,6 +435,8 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
@@ -442,6 +460,8 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
@@ -573,6 +593,7 @@ github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlp
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
@@ -622,7 +643,11 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
@@ -770,6 +795,8 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -868,6 +895,7 @@ gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
type ApiServer struct {
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func (s *ApiServer) Launch() {
|
||||
s.server = &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: setupRoute(),
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
s.server.SetKeepAlivesEnabled(true)
|
||||
|
||||
go (func() error {
|
||||
err := s.server.ListenAndServe()
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
ctrl.Log.Error(err, "failed to start the server")
|
||||
}
|
||||
return err
|
||||
})()
|
||||
}
|
||||
|
||||
func (s *ApiServer) Shutdown(ctx context.Context) error {
|
||||
ctrl.Log.Info("sever shutting down")
|
||||
return s.server.Shutdown(ctx)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package apis
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
type Environment struct {
|
||||
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:"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"`
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
const querymodeKey = "appQuerymode"
|
||||
|
||||
// Apps related handlers
|
||||
func CreateApps(c *gin.Context) {
|
||||
|
||||
}
|
||||
|
||||
func UpdateApps(c *gin.Context) {
|
||||
}
|
||||
|
||||
func GetApps(c *gin.Context) {
|
||||
envName := c.Param("envName")
|
||||
appName := c.Param("appName")
|
||||
queryMode, found := c.GetQuery(querymodeKey)
|
||||
if !found {
|
||||
panic("no repoUrl in update")
|
||||
}
|
||||
ctrl.Log.Info("Get an application request for", "envName", envName, "appName", appName, "queryMdoe", queryMode)
|
||||
}
|
||||
|
||||
func ListApps(c *gin.Context) {
|
||||
}
|
||||
|
||||
func DeleteApps(c *gin.Context) {
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/server/apis"
|
||||
"github.com/cloud-native-application/rudrx/pkg/server/util"
|
||||
)
|
||||
|
||||
// ENV related handlers
|
||||
func CreateEnv(c *gin.Context) {
|
||||
var envConfig apis.Environment
|
||||
if err := c.ShouldBindJSON(&envConfig); err != nil {
|
||||
util.HandleError(c, util.InvalidArgument, "the create environment request body is invalid")
|
||||
return
|
||||
}
|
||||
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 a get environment request", "envName", envName)
|
||||
|
||||
// TODO: implement this
|
||||
c.JSON(http.StatusOK, apis.Environment{
|
||||
EnvironmentName: envName,
|
||||
Namespace: "test",
|
||||
})
|
||||
}
|
||||
|
||||
func ListEnv(c *gin.Context) {
|
||||
}
|
||||
|
||||
func DeleteEnv(c *gin.Context) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package handler
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func GetVersion(c *gin.Context) {
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
// repo related handlers
|
||||
const (
|
||||
repoUrlKey = "repoUrl"
|
||||
)
|
||||
|
||||
func UpdateDefinition(c *gin.Context) {
|
||||
//ctx := util.GetContext(c)
|
||||
categoryName := c.Param("categoryName")
|
||||
definitionName := c.Param("definitionName")
|
||||
repoUrl, found := c.GetQuery(repoUrlKey)
|
||||
if !found {
|
||||
panic("no repoUrl in update")
|
||||
}
|
||||
ctrl.Log.Info("Get Update Repo Definition request for", "categoryName", categoryName, "definitionName", definitionName, "repoUrl", repoUrl)
|
||||
}
|
||||
|
||||
func GetDefinition(c *gin.Context) {
|
||||
categoryName := c.Param("categoryName")
|
||||
definitionName := c.Param("definitionName")
|
||||
repoUrl, found := c.GetQuery(repoUrlKey)
|
||||
if !found {
|
||||
panic("no repoUrl in update")
|
||||
}
|
||||
ctrl.Log.Info("Get Repo Definition request for", "categoryName", categoryName, "definitionName", definitionName, "repoUrl", repoUrl)
|
||||
}
|
||||
|
||||
func ListDefinition(c *gin.Context) {
|
||||
categoryName := c.Param("categoryName")
|
||||
repoUrl, found := c.GetQuery(repoUrlKey)
|
||||
if !found {
|
||||
panic("no repoUrl in update")
|
||||
}
|
||||
ctrl.Log.Info("Get Repo Definition request for", "categoryName", categoryName, repoUrl)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package handler
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// Scope related handlers
|
||||
func CreateScope(c *gin.Context) {
|
||||
}
|
||||
|
||||
func UpdateScope(c *gin.Context) {
|
||||
}
|
||||
|
||||
func GetScope(c *gin.Context) {
|
||||
}
|
||||
|
||||
func ListScope(c *gin.Context) {
|
||||
}
|
||||
|
||||
func DeleteScope(c *gin.Context) {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package handler
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// Trait related handlers
|
||||
func CreateTrait(c *gin.Context) {
|
||||
}
|
||||
|
||||
func UpdateTrait(c *gin.Context) {
|
||||
}
|
||||
|
||||
func GetTrait(c *gin.Context) {
|
||||
}
|
||||
|
||||
func ListTrait(c *gin.Context) {
|
||||
}
|
||||
|
||||
func DeleteTrait(c *gin.Context) {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package handler
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// Workload related handlers
|
||||
func CreateWorkload(c *gin.Context) {
|
||||
}
|
||||
|
||||
func UpdateWorkload(c *gin.Context) {
|
||||
}
|
||||
|
||||
func GetWorkload(c *gin.Context) {
|
||||
}
|
||||
|
||||
func ListWorkload(c *gin.Context) {
|
||||
}
|
||||
|
||||
func DeleteWorkload(c *gin.Context) {
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/cloud-native-application/rudrx/pkg/server/handler"
|
||||
"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 | %s\n",
|
||||
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
|
||||
param.StatusCode,
|
||||
param.Latency,
|
||||
param.ClientIP,
|
||||
param.Method,
|
||||
param.Path,
|
||||
param.ErrorMessage,
|
||||
)
|
||||
},
|
||||
}
|
||||
router.Use(gin.LoggerWithConfig(loggerConfig))
|
||||
router.Use(util.SetRequestID())
|
||||
router.Use(util.SetContext())
|
||||
router.Use(gin.Recovery())
|
||||
router.Use(util.ValidateHeaders())
|
||||
|
||||
// all requests start with /api
|
||||
api := router.Group(util.RootPath)
|
||||
// env related operation
|
||||
envs := api.Group(util.EnvironmentPath)
|
||||
{
|
||||
envs.POST("/", handler.CreateEnv)
|
||||
envs.GET("/:envName", handler.GetEnv)
|
||||
envs.GET("/", handler.ListEnv)
|
||||
envs.DELETE("/:envName", handler.DeleteEnv)
|
||||
// app related operation
|
||||
apps := envs.Group("/:envName/apps")
|
||||
{
|
||||
apps.POST("/", handler.CreateApps)
|
||||
apps.GET("/:appName", handler.GetApps)
|
||||
apps.PUT("/:appName", handler.UpdateApps)
|
||||
apps.GET("/", handler.ListApps)
|
||||
apps.DELETE("/:appName", handler.DeleteApps)
|
||||
}
|
||||
}
|
||||
// workload related api
|
||||
workload := api.Group(util.WorkloadDefinitionPath)
|
||||
{
|
||||
workload.POST("/", handler.CreateWorkload)
|
||||
workload.GET("/:workloadName", handler.GetWorkload)
|
||||
workload.PUT("/:workloadName", handler.UpdateWorkload)
|
||||
workload.GET("/", handler.ListWorkload)
|
||||
workload.DELETE("/:workloadName", handler.DeleteWorkload)
|
||||
}
|
||||
// trait related api
|
||||
trait := api.Group(util.TraitDefinitionPath)
|
||||
{
|
||||
trait.POST("/", handler.CreateTrait)
|
||||
trait.GET("/:traitName", handler.GetTrait)
|
||||
trait.PUT("/:traitName", handler.UpdateTrait)
|
||||
trait.GET("/", handler.ListTrait)
|
||||
trait.DELETE("/:traitName", handler.DeleteTrait)
|
||||
}
|
||||
// scope related api
|
||||
scopes := api.Group(util.ScopeDefinitionPath)
|
||||
{
|
||||
scopes.POST("/", handler.CreateScope)
|
||||
scopes.GET("/:scopeName", handler.GetScope)
|
||||
scopes.PUT("/:scopeName", handler.UpdateScope)
|
||||
scopes.GET("/", handler.ListScope)
|
||||
scopes.DELETE("/:scopeName", handler.DeleteScope)
|
||||
}
|
||||
|
||||
// scope related api
|
||||
repo := api.Group(util.RepoPath)
|
||||
{
|
||||
repo.GET("/:categoryName/:definitionName", handler.GetDefinition)
|
||||
repo.PUT("/:categoryName/:definitionName", handler.UpdateDefinition)
|
||||
repo.GET("/:categoryName", handler.ListDefinition)
|
||||
}
|
||||
// version
|
||||
api.GET(util.VersionPath, handler.GetVersion)
|
||||
// default
|
||||
router.NoRoute(util.NoRoute())
|
||||
|
||||
return router
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
// Code defines the error code type.
|
||||
type Code int
|
||||
|
||||
// Be careful, below constants must be added to the errorDetails map.
|
||||
// All code should be defined between StartMarker and EndMarker
|
||||
const (
|
||||
startMarker Code = iota
|
||||
PathNotSupported
|
||||
InvalidArgument
|
||||
UnsupportedMediaType
|
||||
// End marker
|
||||
endMarker
|
||||
)
|
||||
|
||||
type errorDetail struct {
|
||||
ID string
|
||||
StatusCode int
|
||||
Message string
|
||||
}
|
||||
|
||||
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'"},
|
||||
}
|
||||
|
||||
// ID returns the error ID.
|
||||
func (c Code) ID() string {
|
||||
return errorDetails[c].ID
|
||||
}
|
||||
|
||||
// StatusCode returns the http status code.
|
||||
func (c Code) StatusCode() int {
|
||||
return errorDetails[c].StatusCode
|
||||
}
|
||||
|
||||
// Message returns the detailed error message.
|
||||
func (c Code) Message() string {
|
||||
return errorDetails[c].Message
|
||||
}
|
||||
|
||||
// ConstructError returns a new OpError.
|
||||
func ConstructError(ec Code, a ...interface{}) error {
|
||||
msg := ""
|
||||
// the number of keys should be equal to the number of placeholders defined in ErrorCode.Message.
|
||||
c := strings.Count(ec.Message(), "%")
|
||||
if a == nil && c > 0 ||
|
||||
a != nil && (c != len(a) || a[0] == nil) {
|
||||
ctrl.Log.Error(fmt.Errorf("Args '%v' do not match placeholders in the msg '%s'", a, ec.Message()),
|
||||
"Invalid error message argument")
|
||||
} else if a == nil || len(a) == 0 || a[0] == nil {
|
||||
msg = ec.Message()
|
||||
} else {
|
||||
msg = fmt.Sprintf(ec.Message(), a...)
|
||||
}
|
||||
|
||||
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()} )
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mime"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/satori/go.uuid"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// Header Keys
|
||||
const (
|
||||
// ContextKey is used as key to set/get context.
|
||||
ContextKey = "context"
|
||||
|
||||
// HeaderRequestID is used as key to set/get request id.
|
||||
HeaderRequestID = "x-fc-request-id"
|
||||
|
||||
// ContentTypeJSON : json
|
||||
ContentTypeJSON = "application/json"
|
||||
|
||||
// ContentTypeOctetStream: octet stream
|
||||
ContentTypeOctetStream = "application/octet-stream"
|
||||
|
||||
// HeaderTraceID is header name for trace id.
|
||||
HeaderTraceID = "x-fc-trace-id"
|
||||
|
||||
HeaderContentType = "content-Type"
|
||||
|
||||
HeaderContentLength = "content-Length"
|
||||
|
||||
// ServiceLogFields shared key service log fields
|
||||
ServiceLogFields = "ServiceLogFields"
|
||||
|
||||
// HeaderClientIP is the real IP of the remote client
|
||||
HeaderClientIP = "clientIP"
|
||||
)
|
||||
|
||||
const (
|
||||
// RESTful API paths
|
||||
RootPath = "/api"
|
||||
EnvironmentPath = "/envs"
|
||||
ApplicationPath = "/apps"
|
||||
WorkloadDefinitionPath = "/workloads"
|
||||
ScopeDefinitionPath = "/scopes"
|
||||
TraitDefinitionPath = "/traits"
|
||||
RepoPath = "/category"
|
||||
VersionPath = "/version"
|
||||
)
|
||||
|
||||
const contextLoggerKey = "logger"
|
||||
|
||||
//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, c.Request.Method, c.Request.URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
//generateRequestID :Get request id
|
||||
func generateRequestID() string {
|
||||
return uuid.NewV4().String()
|
||||
}
|
||||
|
||||
// SetRequestID ...
|
||||
func SetRequestID() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestID := ""
|
||||
traceID := ""
|
||||
if traceID = c.Request.Header.Get(HeaderTraceID); traceID != "" {
|
||||
requestID = traceID
|
||||
} else if requestID = c.Request.Header.Get(HeaderRequestID); requestID != "" {
|
||||
traceID = requestID
|
||||
} else {
|
||||
requestID = generateRequestID()
|
||||
traceID = requestID
|
||||
}
|
||||
c.Set(HeaderRequestID, requestID)
|
||||
c.Set(HeaderClientIP, c.ClientIP())
|
||||
c.Set(HeaderTraceID, traceID)
|
||||
}
|
||||
}
|
||||
|
||||
// SetContext :Set context metadata for request
|
||||
// Before get request
|
||||
func SetContext() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
reqID := c.MustGet(HeaderRequestID).(string)
|
||||
ctx, cancel := context.WithCancel(c.Request.Context())
|
||||
fields := make(map[string]zapcore.Field)
|
||||
mctx := context.WithValue(ctx, ServiceLogFields, fields)
|
||||
fctx := context.WithValue(mctx, HeaderRequestID, reqID)
|
||||
c.Set(ContextKey, fctx)
|
||||
c.Next()
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// get the context from the gin context
|
||||
func GetContext(c *gin.Context) context.Context {
|
||||
return c.MustGet(ContextKey).(context.Context)
|
||||
}
|
||||
|
||||
// ValidateHeaders validates the common headers.
|
||||
//
|
||||
// It reports one problem at a time.
|
||||
func ValidateHeaders() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// It's ok to not specify Content-Type header, but it should be correct if it's specified.
|
||||
contentType := c.Request.Header.Get(HeaderContentType)
|
||||
if len(contentType) != 0 {
|
||||
mType, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
SetErrorAndAbort(c, UnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
switch mType {
|
||||
case ContentTypeJSON, ContentTypeOctetStream:
|
||||
// Passes.
|
||||
default:
|
||||
SetErrorAndAbort(c, UnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user