Feat: Initialize api for vela dashboard and CLI (#2339)

* Change the web framework to go-restful.
* Some API specifications are defined.
* Some sample code is provided.
This commit is contained in:
barnettZQG
2021-09-26 23:09:23 +08:00
committed by GitHub
parent 6771c688dd
commit 3a310f0402
26 changed files with 1291 additions and 888 deletions
+4 -4
View File
@@ -58,9 +58,6 @@ vela-cli:
kubectl-vela:
$(GOBUILD_ENV) go build -o bin/kubectl-vela -a -ldflags $(LDFLAGS) ./cmd/plugin/main.go
dashboard-build:
cd references/dashboard && npm install && cd ..
doc-gen:
rm -r docs/en/cli/*
go run hack/docgen/gen.go
@@ -98,6 +95,9 @@ compress:
run:
go run ./cmd/core/main.go --application-revision-limit 5
run-apiserver:
go run ./cmd/apiserver/main.go
# Run go fmt against code
fmt: goimports installcue
go fmt ./...
@@ -239,7 +239,7 @@ manifests: installcue kustomize
./vela-templates/gen_definitions.sh
go run ./vela-templates/gen_addons.go
GOLANGCILINT_VERSION ?= v1.31.0
GOLANGCILINT_VERSION ?= v1.38.0
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
HOSTARCH := $(shell uname -m)
ifeq ($(HOSTARCH),x86_64)
+22 -4
View File
@@ -21,6 +21,8 @@ import (
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"github.com/oam-dev/kubevela/pkg/apiserver/log"
"github.com/oam-dev/kubevela/pkg/apiserver/rest"
@@ -29,14 +31,30 @@ import (
func main() {
s := &server{}
flag.IntVar(&s.restCfg.Port, "port", 8000, "The port number used to serve the http APIs.")
flag.StringVar(&s.restCfg.BindAddr, "bind-addr", "0.0.0.0:8000", "The bind address used to serve the http APIs.")
flag.StringVar(&s.restCfg.MetricPath, "metrics-path", "/metrics", "The path to expose the metrics.")
flag.StringVar(&s.restCfg.Datastore.Type, "datastore-type", "kubeapi", "Metadata storage driver type, support kubeapi and mongodb")
flag.StringVar(&s.restCfg.Datastore.Database, "datastore-database", "kubevela", "Metadata storage database name, takes effect when the storage driver is mongodb.")
flag.StringVar(&s.restCfg.Datastore.URL, "datastore-url", "", "Metadata storage database url,takes effect when the storage driver is mongodb.")
flag.Parse()
if err := s.run(); err != nil {
log.Logger.Errorf("failed to run apiserver: %v", err)
srvc := make(chan struct{})
go func() {
if err := s.run(); err != nil {
log.Logger.Errorf("failed to run apiserver: %v", err)
}
close(srvc)
}()
var term = make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
select {
case <-term:
log.Logger.Infof("Received SIGTERM, exiting gracefully...")
case <-srvc:
os.Exit(1)
}
log.Logger.Infof("See you next time!")
}
type server struct {
+5 -1
View File
@@ -15,11 +15,15 @@ require (
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.7.1
github.com/emicklei/go-restful-openapi/v2 v2.3.0
github.com/emicklei/go-restful/v3 v3.0.0-rc2
github.com/evanphx/json-patch v4.11.0+incompatible
github.com/fatih/color v1.12.0
github.com/gertd/go-pluralize v0.1.7
github.com/getkin/kin-openapi v0.34.0
github.com/go-logr/logr v0.4.0
github.com/go-openapi/spec v0.19.8
github.com/go-playground/validator/v10 v10.9.0
github.com/google/go-cmp v0.5.6
github.com/google/go-github/v32 v32.1.0
github.com/gosuri/uitable v0.0.4
@@ -27,7 +31,6 @@ require (
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
github.com/imdario/mergo v0.3.12
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/labstack/echo/v4 v4.5.0
github.com/mitchellh/hashstructure/v2 v2.0.1
github.com/oam-dev/cluster-gateway v0.0.0-20210907072424-2f8720b116f8
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28
@@ -45,6 +48,7 @@ require (
github.com/tidwall/gjson v1.6.8
github.com/wercker/stern v0.0.0-20190705090245-4fa46dd6987f
github.com/wonderflow/cert-manager-api v1.0.3
go.mongodb.org/mongo-driver v1.3.2
go.uber.org/zap v1.18.1
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+34 -18
View File
@@ -402,6 +402,10 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful-openapi/v2 v2.3.0 h1:tDgSCzQrkk4N+Isos0zGBYX/GTINjmQuP9BvITbEe38=
github.com/emicklei/go-restful-openapi/v2 v2.3.0/go.mod h1:bs67E3SEVgSmB3qDuRLqpS0NcpheqtsCCMhW2/jml1E=
github.com/emicklei/go-restful/v3 v3.0.0-rc2 h1:UkWzdUozgtjQzYuqSNQy+PuYxD4/DCzYucakgzWKolU=
github.com/emicklei/go-restful/v3 v3.0.0-rc2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/proto v1.6.15 h1:XbpwxmuOPrdES97FrSfpyy67SSCV/wBIKXqgJzh6hNw=
github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
@@ -558,6 +562,7 @@ github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.6/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
@@ -569,11 +574,20 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-openapi/validate v0.19.8/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.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
@@ -642,8 +656,6 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
@@ -685,6 +697,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
@@ -959,6 +972,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.0 h1:wJbzvpYMVGG9iTI9VxpnNZfd4DzMPoCWze3GgSqz8yg=
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
@@ -970,8 +984,9 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
@@ -988,10 +1003,6 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg=
github.com/kyokomi/emoji v2.2.4+incompatible h1:np0woGKwx9LiHAQmwZx79Oc0rHpNw3o+3evou4BEPv4=
github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
github.com/labstack/echo/v4 v4.5.0 h1:JXk6H5PAw9I3GwizqUHhYyS4f45iyGebR/c1xNCeOCY=
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
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=
@@ -999,6 +1010,8 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm
github.com/ldez/gomoddirectives v0.2.1/go.mod h1:sGicqkRgBOg//JfpXwkB9Hj0X5RyJ7mlACM5B9f6Me4=
github.com/ldez/tagliatelle v0.2.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88=
github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -1047,7 +1060,6 @@ github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6I
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -1161,7 +1173,6 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nishanths/exhaustive v0.1.0/go.mod h1:S1j9110vxV1ECdCudXRkeMnFQ/DQk9ajLT0Uf2MYZQQ=
github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ=
@@ -1262,6 +1273,7 @@ github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rK
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.0.0-20180311214515-816c9085562c/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -1358,8 +1370,10 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk=
@@ -1508,12 +1522,8 @@ github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVU
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
@@ -1527,7 +1537,9 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/wonderflow/cert-manager-api v1.0.3 h1:xQQMkJNQ12oYyy00jOQUlSKgdraApaURxv3PHFdVTfA=
github.com/wonderflow/cert-manager-api v1.0.3/go.mod h1:1Se7MSg11/eNYlo4fWv6vOM55/jTBMOzg2DN1kVFiSc=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo=
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1591,6 +1603,7 @@ go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
go.mongodb.org/mongo-driver v1.3.2 h1:IYppNjEV/C+/3VPbhHVxQ4t04eVW0cLp0/pNdW++6Ug=
go.mongodb.org/mongo-driver v1.3.2/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE=
go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@@ -1684,8 +1697,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1925,9 +1939,11 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
@@ -1950,7 +1966,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
@@ -2236,8 +2251,9 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+57
View File
@@ -0,0 +1,57 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package datastore
import (
"context"
)
// Config datastore config
type Config struct {
Type string
URL string
Database string
}
// DataStore datastore interface
type DataStore interface {
Add(ctx context.Context, kind string, entity interface{}) error
Put(ctx context.Context, kind, name string, entity interface{}) error
Delete(ctx context.Context, kind, name string) error
Get(ctx context.Context, kind, name string, decodeTo interface{}) error
// Find executes a find command and returns an iterator over the matching items.
Find(ctx context.Context, kind string) (Iterator, error)
FindOne(ctx context.Context, kind, name string) (Iterator, error)
IsExist(ctx context.Context, kind, name string) (bool, error)
}
// Iterator dataset query
type Iterator interface {
// Next gets the next item for this cursor.
Next(ctx context.Context) bool
// Decode will unmarshal the current item into given entity.
Decode(entity interface{}) error
Close(ctx context.Context) error
}
@@ -0,0 +1,67 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubeapi
import (
"context"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
)
type kubeapi struct {
// kubeclient client.Client
}
// New new kubeapi datastore instance
func New(ctx context.Context, cfg datastore.Config) (datastore.DataStore, error) {
return &kubeapi{}, nil
}
// Add add data model
func (m *kubeapi) Add(ctx context.Context, kind string, entity interface{}) error {
return nil
}
// Get get data model
func (m *kubeapi) Get(ctx context.Context, kind, name string, decodeTo interface{}) error {
return nil
}
// Put update data model
func (m *kubeapi) Put(ctx context.Context, kind, name string, entity interface{}) error {
return nil
}
// Find find data model
func (m *kubeapi) Find(ctx context.Context, kind string) (datastore.Iterator, error) {
return nil, nil
}
// FindOne find one data model
func (m *kubeapi) FindOne(ctx context.Context, kind, name string) (datastore.Iterator, error) {
return nil, nil
}
// IsExist determine whether data exists.
func (m *kubeapi) IsExist(ctx context.Context, kind, name string) (bool, error) {
return true, nil
}
// Delete delete data
func (m *kubeapi) Delete(ctx context.Context, kind, name string) error {
return nil
}
@@ -0,0 +1,43 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mongodb
import (
"context"
"go.mongodb.org/mongo-driver/mongo"
)
// Iterator mongo iterator implementation
type Iterator struct {
cur *mongo.Cursor
}
// Close iterator close
func (i *Iterator) Close(ctx context.Context) error {
return i.cur.Close(ctx)
}
// Next read next data
func (i *Iterator) Next(ctx context.Context) bool {
return i.cur.Next(ctx)
}
// Decode decode data
func (i *Iterator) Decode(entity interface{}) error {
return i.cur.Decode(entity)
}
+137
View File
@@ -0,0 +1,137 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mongodb
import (
"context"
"errors"
"fmt"
"cuelang.org/go/pkg/strings"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
)
type mongodb struct {
client *mongo.Client
database string
}
// New new mongodb datastore instance
func New(ctx context.Context, cfg datastore.Config) (datastore.DataStore, error) {
if strings.HasPrefix(cfg.URL, "mongodb://") {
cfg.URL = fmt.Sprintf("mongodb://%s", cfg.URL)
}
clientOpts := options.Client().ApplyURI(cfg.URL)
client, err := mongo.Connect(ctx, clientOpts)
if err != nil {
return nil, err
}
m := &mongodb{
client: client,
database: cfg.Database,
}
return m, nil
}
// Add add data model
func (m *mongodb) Add(ctx context.Context, kind string, entity interface{}) error {
collection := m.client.Database(m.database).Collection(kind)
_, err := collection.InsertOne(ctx, entity)
if err != nil {
return err
}
return nil
}
// Get get data model
func (m *mongodb) Get(ctx context.Context, kind, name string, decodeTo interface{}) error {
collection := m.client.Database(m.database).Collection(kind)
return collection.FindOne(ctx, makeNameFilter(name)).Decode(decodeTo)
}
// Put update data model
func (m *mongodb) Put(ctx context.Context, kind, name string, entity interface{}) error {
collection := m.client.Database(m.database).Collection(kind)
_, err := collection.UpdateOne(ctx, makeNameFilter(name), makeEntityUpdate(entity))
if err != nil {
return err
}
return nil
}
// Find find data model
func (m *mongodb) Find(ctx context.Context, kind string) (datastore.Iterator, error) {
collection := m.client.Database(m.database).Collection(kind)
// bson.D{{}} specifies 'all documents'
filter := bson.D{}
cur, err := collection.Find(ctx, filter)
if err != nil {
return nil, err
}
return &Iterator{cur: cur}, nil
}
// FindOne find one data model
func (m *mongodb) FindOne(ctx context.Context, kind, name string) (datastore.Iterator, error) {
collection := m.client.Database(m.database).Collection(kind)
filter := bson.M{"name": name}
cur, err := collection.Find(ctx, filter)
if err != nil {
return nil, err
}
return &Iterator{cur: cur}, nil
}
// IsExist determine whether data exists.
func (m *mongodb) IsExist(ctx context.Context, kind, name string) (bool, error) {
collection := m.client.Database(m.database).Collection(kind)
err := collection.FindOne(ctx, makeNameFilter(name)).Err()
if errors.Is(err, mongo.ErrNoDocuments) {
return false, nil
} else if err != nil {
return false, err
}
return true, nil
}
// Delete delete data
func (m *mongodb) Delete(ctx context.Context, kind, name string) error {
collection := m.client.Database(m.database).Collection(kind)
// delete at most one document in which the "name" field is "Bob" or "bob"
// specify the SetCollation option to provide a collation that will ignore case for string comparisons
opts := options.Delete().SetCollation(&options.Collation{
Locale: "en_US",
Strength: 1,
CaseLevel: false,
})
_, err := collection.DeleteOne(ctx, makeNameFilter(name), opts)
return err
}
func makeNameFilter(name string) bson.D {
return bson.D{{Key: "name", Value: name}}
}
func makeEntityUpdate(entity interface{}) bson.M {
return bson.M{"$set": entity}
}
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package apis
package v1
import (
"github.com/oam-dev/kubevela/pkg/apiserver/model"
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package apis
package v1
import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
+250
View File
@@ -0,0 +1,250 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"time"
)
// CreateClusterRequest request parameters to create a cluster
type CreateClusterRequest struct {
Name string `json:"name" validate:"required"`
Description string `json:"description,omitempty"`
Icon string `json:"icon"`
KubeConfig string `json:"kubeConfig" validate:"required_without=kubeConfigSecret"`
KubeConfigSecret string `json:"kubeConfigSecret,omitempty" validate:"required_without=kubeConfig"`
Labels map[string]string `json:"labels,omitempty"`
}
// DetailClusterResponse cluster detail information model
type DetailClusterResponse struct {
ClusterBase
ResourceInfo ClusterResourceInfo `json:"resourceInfo"`
// remote manage url, eg. ACK cluster manage url.
RemoteManageURL string `json:"remoteManageURL,omitempty"`
// Dashboard URL
DashboardURL string `json:"dashboardURL,omitempty"`
}
// ClusterResourceInfo resource info of cluster
type ClusterResourceInfo struct {
WorkerNumber int `json:"workerNumber"`
MasterNumber int `json:"masterNumber"`
MemoryCapacity int64 `json:"memoryCapacity"`
CPUCapacity int64 `json:"cpuCapacity"`
GPUCapacity int64 `json:"gpuCapacity,omitempty"`
StorageClassList []string `json:"storageClassList,omitempty"`
}
// ListClusterResponse list cluster
type ListClusterResponse struct {
Clusters []ClusterBase `json:"clusters"`
}
// ClusterBase cluster base model
type ClusterBase struct {
Name string `json:"name"`
Description string `json:"description"`
Icon string `json:"icon"`
Labels map[string]string `json:"labels"`
Status string `json:"status"`
Reason string `json:"reason"`
}
// ListClusterAddonResponse list all addon of the cluster
type ListClusterAddonResponse struct {
Addons []ClusterAddonBase `json:"addons"`
}
// ClusterAddonBase cluster addon base model
type ClusterAddonBase struct {
Name string `json:"name"`
Description string `json:"description"`
Status string `json:"status"`
}
// DeatilClusterAddonResponse detail addon info
type DeatilClusterAddonResponse struct {
ClusterAddonBase
}
// ListApplicationResponse list applications by query params
type ListApplicationResponse struct {
Applications []*ApplicationBase `json:"applications"`
}
// ApplicationBase application base model
type ApplicationBase struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Description string `json:"description"`
CreateTime time.Time `json:"createTime"`
UpdateTime time.Time `json:"updateTime"`
Icon string `json:"icon"`
Labels map[string]string `json:"labels,omitempty"`
ClusterBindList []ClusterBase `json:"clusterList,omitempty"`
Status string `json:"status"`
GatewayRuleList []GatewayRule `json:"gatewayRule"`
}
// RuleType gateway rule type
type RuleType string
const (
// HTTPRule Layer 7 HTTP policy.
HTTPRule RuleType = "http"
// StreamRule Layer 4 policy, such as TCP and UDP
StreamRule RuleType = "stream"
)
// GatewayRule application gateway rule
type GatewayRule struct {
RuleType RuleType `json:"ruleType"`
Address string `json:"address"`
Protocol string `json:"protocol"`
ComponentName string `json:"componentName"`
ComponentPort int32 `json:"componentPort"`
}
// CreateApplicationRequest create application request body
type CreateApplicationRequest struct {
Name string `json:"name" validate:"required"`
Namespace string `json:"namespace" validate:"required"`
Description string `json:"description"`
Icon string `json:"icon"`
Labels map[string]string `json:"labels,omitempty"`
ClusterList []string `json:"clusterList,omitempty"`
YamlConfig string `json:"yamlConfig,omitempty"`
}
// DetailApplicationResponse application detail
type DetailApplicationResponse struct {
ApplicationBase
Policies []string `json:"policies"`
Status string `json:"status"`
ResourceInfo ApplicationResourceInfo `json:"resourceInfo"`
WorkflowStatus []WorkflowStepStatus `json:"workflowStatus"`
}
// WorkflowStepStatus workflow step status model
type WorkflowStepStatus struct {
Name string `json:"name"`
Status string `json:"status"`
TakeTime time.Duration `json:"takeTime"`
}
// ApplicationResourceInfo application-level resource consumption statistics
type ApplicationResourceInfo struct {
ComponentNum int `json:"componentNum"`
// Others, such as: Memory、CPU、GPU、Storage
}
// ComponentBase component base model
type ComponentBase struct {
Name string `json:"name"`
Description string `json:"description"`
Labels map[string]string `json:"labels,omitempty"`
ComponentType string `json:"componentType"`
BindClusters []string `json:"bindClusters"`
Icon string `json:"icon,omitempty"`
DependOn []string `json:"dependOn"`
Creator string `json:"creator,omitempty"`
DeployVersion string `json:"deployVersion"`
}
// ComponentListResponse list component
type ComponentListResponse struct {
Components []ComponentBase `json:"components"`
}
// CreateComponentRequest create component request model
type CreateComponentRequest struct {
ApplicationName string `json:"appName" validate:"required"`
Name string `json:"name" validate:"required"`
Description string `json:"description"`
Labels map[string]string `json:"labels,omitempty"`
ComponentType string `json:"componentType" validate:"required"`
BindClusters []string `json:"bindClusters"`
Properties string `json:"properties,omitempty"`
}
// CreateApplicationTemplateRequest create app template request model
type CreateApplicationTemplateRequest struct {
TemplateName string `json:"templateName" validate:"required"`
Version string `json:"version" validate:"required"`
Description string `json:"description"`
}
// ApplicationTemplateBase app template model
type ApplicationTemplateBase struct {
TemplateName string `json:"templateName"`
Versions []*ApplicationTemplateVersion `json:"versions,omitempty"`
}
// ApplicationTemplateVersion template version model
type ApplicationTemplateVersion struct {
Version string `json:"version"`
Description string `json:"description"`
CreateUser string `json:"createUser"`
CreateTime time.Time `json:"createTime"`
UpdateTime time.Time `json:"updateTime"`
}
// ListNamespaceResponse namesace list model
type ListNamespaceResponse struct {
Namespaces []NamesapceBase `json:"namesapces"`
}
// NamesapceBase namespace base model
type NamesapceBase struct {
Name string `json:"name"`
Description string `json:"description"`
}
// CreateNamespaceRequest create namespace request body
type CreateNamespaceRequest struct {
Name string `json:"name" validate:"required"`
Description string `json:"description"`
}
// NamesapceDetailResponse namespace detail response
type NamesapceDetailResponse struct {
NamesapceBase
ClusterBind map[string]string `json:"clusterBind"`
}
// ListComponentDefinitionResponse list component dedinition response model
type ListComponentDefinitionResponse struct {
ComponentDefinitions []ComponentDefinitionBase `json:"componentDefinitions"`
}
// ComponentDefinitionBase component definition base model
type ComponentDefinitionBase struct {
Name string `json:"name"`
Description string `json:"description"`
Icon string `json:"icon"`
RequiredParams []Param `json:"requiredParams"`
}
// Param For rendering forms
type Param struct {
Key string `json:"key"`
Name string `json:"name"`
DefaultValue interface{} `json:"defaultValue"`
Type string `json:"type"`
Description string `json:"description"`
}
+82 -51
View File
@@ -21,20 +21,28 @@ import (
"fmt"
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"sigs.k8s.io/controller-runtime/pkg/client"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore/kubeapi"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore/mongodb"
"github.com/oam-dev/kubevela/pkg/apiserver/log"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/services"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/webservice"
)
var _ APIServer = &restServer{}
// Config config for server
type Config struct {
Port int
// api server bind address
BindAddr string
// monitor metric path
MetricPath string
// Datastore config
Datastore datastore.Config
}
// APIServer interface for call api server
@@ -43,45 +51,38 @@ type APIServer interface {
}
type restServer struct {
server *echo.Echo
k8sClient client.Client
cfg Config
webContainer *restful.Container
cfg Config
dataStore datastore.DataStore
}
// New create restserver with config data
func New(cfg Config) (APIServer, error) {
client, err := common.NewK8sClient()
if err != nil {
return nil, fmt.Errorf("create client for clusterService failed")
func New(cfg Config) (a APIServer, err error) {
var ds datastore.DataStore
switch cfg.Datastore.Type {
case "mongodb":
ds, err = mongodb.New(context.Background(), cfg.Datastore)
if err != nil {
return nil, fmt.Errorf("create mongodb datastore instance failure %w", err)
}
case "kubeapi":
ds, err = kubeapi.New(context.Background(), cfg.Datastore)
if err != nil {
return nil, fmt.Errorf("create mongodb datastore instance failure %w", err)
}
default:
return nil, fmt.Errorf("not support datastore type %s", cfg.Datastore.Type)
}
s := &restServer{
server: newEchoInstance(),
k8sClient: client,
cfg: cfg,
webContainer: restful.NewContainer(),
cfg: cfg,
dataStore: ds,
}
return s, nil
}
func newEchoInstance() *echo.Echo {
e := echo.New()
e.HideBanner = true
e.Use(middleware.Gzip())
e.Use(middleware.Logger())
e.Pre(middleware.RemoveTrailingSlash())
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
AllowCredentials: true,
MaxAge: 86400,
}))
return e
}
func (s *restServer) Run(ctx context.Context) error {
webservice.Init(ctx)
err := s.registerServices()
if err != nil {
return err
@@ -94,28 +95,58 @@ func (s *restServer) registerServices() error {
/* ************************************************************** */
/* ************* Open API Route Group ***************** */
/* ************************************************************** */
openapi := s.server.Group("/v1")
// catalog
catalogService := services.NewCatalogService(s.k8sClient)
openapi.GET("/catalogs", catalogService.ListCatalogs)
openapi.POST("/catalogs", catalogService.AddCatalog)
openapi.PUT("/catalogs", catalogService.UpdateCatalog)
openapi.GET("/catalogs/:catalogName", catalogService.GetCatalog)
openapi.DELETE("/catalogs/:catalogName", catalogService.DelCatalog)
// Add container filter to enable CORS
cors := restful.CrossOriginResourceSharing{
ExposeHeaders: []string{},
AllowedHeaders: []string{"Content-Type", "Accept"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"},
CookiesAllowed: true,
Container: s.webContainer}
s.webContainer.Filter(cors.Filter)
// application
applicationService := services.NewApplicationService(s.k8sClient)
openapi.GET("/namespaces/:namespace/applications/:appname", applicationService.GetApplication)
openapi.POST("/namespaces/:namespace/applications/:appname", applicationService.CreateOrUpdateApplication)
openapi.DELETE("/namespaces/:namespace/applications/:appname", applicationService.DeleteApplication)
// Add container filter to respond to OPTIONS
s.webContainer.Filter(s.webContainer.OPTIONSFilter)
// Regist all custom webservice
for _, handler := range webservice.GetRegistedWebService() {
s.webContainer.Add(handler.GetWebService())
}
config := restfulspec.Config{
WebServices: s.webContainer.RegisteredWebServices(), // you control what services are visible
APIPath: "/apidocs.json",
PostBuildSwaggerObjectHandler: enrichSwaggerObject}
s.webContainer.Add(restfulspec.NewOpenAPIService(config))
return nil
}
func enrichSwaggerObject(swo *spec.Swagger) {
swo.Info = &spec.Info{
InfoProps: spec.InfoProps{
Title: "Kubevela api doc",
Description: "Kubevela api doc",
Contact: &spec.ContactInfo{
ContactInfoProps: spec.ContactInfoProps{
Name: "kubevela",
Email: "feedback@mail.kubevela.io",
URL: "https://kubevela.io/",
},
},
License: &spec.License{
LicenseProps: spec.LicenseProps{
Name: "Apache License 2.0",
URL: "https://github.com/oam-dev/kubevela/blob/master/LICENSE",
},
},
Version: "v1beta1",
},
}
}
func (s *restServer) startHTTP(ctx context.Context) error {
// Start HTTP apiserver
log.Logger.Infof("HTTP APIs are being served on port: %d, ctx: %s", s.cfg.Port, ctx)
addr := fmt.Sprintf(":%d", s.cfg.Port)
return s.server.Start(addr)
log.Logger.Infof("HTTP APIs are being served on: %s, ctx: %s", s.cfg.BindAddr, ctx)
server := &http.Server{Addr: s.cfg.BindAddr, Handler: s.webContainer}
return server.ListenAndServe()
}
-122
View File
@@ -1,122 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package services
import (
"context"
"net/http"
"github.com/labstack/echo/v4"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/apis"
)
// ApplicationService serves as Application Open API for request
type ApplicationService struct {
k8sClient client.Client
}
// NewApplicationService create an application service
func NewApplicationService(kc client.Client) *ApplicationService {
return &ApplicationService{
k8sClient: kc,
}
}
// GetApplication will get application status
// GET /namespaces/<namespace>/applications/<appname>
func (s *ApplicationService) GetApplication(c echo.Context) error {
namespace := c.Param("namespace")
appName := c.Param("appname")
ctx := context.TODO()
var existApp v1beta1.Application
err := s.k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appName}, &existApp)
if err != nil {
if apierrors.IsNotFound(err) {
return c.JSON(http.StatusNotFound, map[string]string{"error": "application does not exist: " + err.Error()})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to get application: " + err.Error()})
}
var appResp = &apis.ApplicationResponse{
APIVersion: existApp.APIVersion,
Kind: existApp.Kind,
Spec: existApp.Spec,
Status: existApp.Status,
}
return c.JSON(http.StatusOK, appResp)
}
// CreateOrUpdateApplication will create or update application
// POST /namespaces/<namespace>/applications/<appname>
func (s *ApplicationService) CreateOrUpdateApplication(c echo.Context) error {
namespace := c.Param("namespace")
name := c.Param("appname")
appReq := new(apis.ApplicationRequest)
if err := c.Bind(appReq); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request body: " + err.Error()})
}
ctx := context.TODO()
var app, existApp v1beta1.Application
app.Namespace = namespace
app.Name = name
app.Spec.Components = appReq.Components
app.Spec.Policies = appReq.Policies
app.Spec.Workflow = appReq.Workflow
err := s.k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, &existApp)
if err != nil {
if !apierrors.IsNotFound(err) {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to get application: " + err.Error()})
}
err = s.k8sClient.Create(ctx, &app)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to create application: " + err.Error()})
}
return c.JSON(http.StatusOK, struct{}{})
}
existApp.Spec = app.Spec
err = s.k8sClient.Update(ctx, &existApp)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to update application: " + err.Error()})
}
return c.JSON(http.StatusOK, struct{}{})
}
// DeleteApplication will delete application
// delete /v1/namespaces/<namespace>/applications/<appname>
func (s *ApplicationService) DeleteApplication(c echo.Context) error {
namespace := c.Param("namespace")
appName := c.Param("appname")
ctx := context.TODO()
var existApp v1beta1.Application
existApp.Namespace = namespace
existApp.Name = appName
err := s.k8sClient.Delete(ctx, &existApp)
if err != nil {
if apierrors.IsNotFound(err) {
return c.JSON(http.StatusNotFound, map[string]string{"error": "application does not exist: " + err.Error()})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "fail to delete application: " + err.Error()})
}
return c.JSON(http.StatusOK, struct{}{})
}
@@ -1,272 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package services
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/apis"
"github.com/oam-dev/kubevela/pkg/utils/common"
)
func TestApplicationCreateOrUpdate(t *testing.T) {
cw := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
appSvc := NewApplicationService(cw)
appComp1 := common2.ApplicationComponent{
Name: "mycomp",
Type: "webservice",
Properties: runtime.RawExtension{Raw: []byte(`{"image":"nginx:v1"}`)},
}
appComp2 := common2.ApplicationComponent{
Name: "mycomp2",
Type: "webservice",
Properties: runtime.RawExtension{Raw: []byte(`{"image":"nginx:v2"}`)},
}
tests := map[string]struct {
appReq *apis.ApplicationRequest
rawReq []byte
name string
namespace string
expHttpCode int
expErr string
expApp *v1beta1.Application
}{
"normal create with only component": {
appReq: &apis.ApplicationRequest{
Components: []common2.ApplicationComponent{appComp1},
},
expHttpCode: 200,
name: "myapp",
namespace: "mynamespace",
expApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common2.ApplicationComponent{appComp1},
},
},
},
"create with bind error": {
rawReq: []byte("XXXX"),
expHttpCode: 400,
name: "myapp",
namespace: "mynamespace",
expErr: "invalid request body: code=400",
},
"normal update with component and trait": {
appReq: &apis.ApplicationRequest{
Components: []common2.ApplicationComponent{appComp1, appComp2},
},
expHttpCode: 200,
name: "myapp",
namespace: "mynamespace",
expApp: &v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common2.ApplicationComponent{appComp1, appComp2},
},
},
},
}
for casename, c := range tests {
var err error
if c.appReq != nil {
c.rawReq, err = json.Marshal(c.appReq)
assert.NoError(t, err, casename)
}
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(c.rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues(c.namespace, c.name)
err = appSvc.CreateOrUpdateApplication(echoCtx)
assert.NoError(t, err, casename)
// check response
assert.Equal(t, c.expHttpCode, rec.Code, casename)
if c.expErr != "" { // compare return error with map type
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
assert.True(t, strings.Contains(gotResp["error"], c.expErr), casename)
} else { // check app spec in fake cluster
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.NoError(t, err, casename)
assert.Equal(t, c.expApp.Spec, appObj.Spec, casename)
}
}
}
func TestApplicationGet(t *testing.T) {
cw := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
appSvc := NewApplicationService(cw)
tests := map[string]struct {
rawReq []byte
name string
namespace string
expHttpCode int
expErr string
expApp *v1beta1.Application
}{
"normal get method for application": {
expHttpCode: 200,
name: "commonName",
namespace: "commonNamespace",
},
"get app failed with resource not found": {
expHttpCode: 404,
name: "notExistName",
namespace: "commonNamespace",
expErr: "application does not exist",
},
}
// create an application for get
createAppForTest(t, appSvc)
for casename, c := range tests {
var err error
req := httptest.NewRequest(http.MethodGet, "/", bytes.NewBuffer(c.rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues(c.namespace, c.name)
err = appSvc.GetApplication(echoCtx)
assert.NoError(t, err, casename)
// check response
assert.Equal(t, c.expHttpCode, rec.Code, casename)
if c.expErr != "" { // compare return error with map type
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
assert.True(t, strings.Contains(gotResp["error"], c.expErr), casename)
} else { // check app spec in fake cluster
var gotResp apis.ApplicationResponse
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.NoError(t, err, casename)
assert.Equal(t, gotResp.APIVersion, appObj.APIVersion, casename)
assert.Equal(t, gotResp.Kind, appObj.Kind, casename)
assert.Equal(t, gotResp.Spec, appObj.Spec, casename)
assert.Equal(t, gotResp.Status, appObj.Status, casename)
}
}
}
func TestApplicationDelete(t *testing.T) {
cw := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
appSvc := NewApplicationService(cw)
tests := map[string]struct {
rawReq []byte
name string
namespace string
expHttpCode int
expErr string
}{
"normal delete method for application": {
expHttpCode: 200,
name: "commonName",
namespace: "commonNamespace",
},
"delete app failed with resource not found": {
expHttpCode: 404,
name: "notExistName",
namespace: "commonNamespace",
expErr: "application does not exist",
},
}
for casename, c := range tests {
// create common app
createAppForTest(t, appSvc)
var err error
req := httptest.NewRequest(http.MethodDelete, "/", bytes.NewBuffer(c.rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues(c.namespace, c.name)
err = appSvc.DeleteApplication(echoCtx)
assert.NoError(t, err, casename)
// check response
assert.Equal(t, c.expHttpCode, rec.Code, casename)
if c.expErr != "" {
gotResp := map[string]string{}
err = json.Unmarshal(rec.Body.Bytes(), &gotResp)
assert.NoError(t, err, casename)
assert.True(t, strings.Contains(gotResp["error"], c.expErr), casename)
} else {
// checkout app status in fake cluster
var appObj v1beta1.Application
err = cw.Get(context.TODO(), client.ObjectKey{Namespace: c.namespace, Name: c.name}, &appObj)
assert.Equal(t, apierrors.IsNotFound(err), true)
}
}
}
func createAppForTest(t *testing.T, appSvc *ApplicationService) {
appComp := common2.ApplicationComponent{
Name: "mycomp",
Type: "webservice",
Properties: runtime.RawExtension{Raw: []byte(`{"image":"nginx:v1"}`)},
}
var appReq = &apis.ApplicationRequest{
Components: []common2.ApplicationComponent{appComp},
}
var rawReq []byte
var err error
if appReq != nil {
rawReq, err = json.Marshal(appReq)
assert.NoError(t, err, "marshal request for create app")
}
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(rawReq))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
echoCtx := echo.New().NewContext(req, rec)
echoCtx.SetParamNames("namespace", "appname")
echoCtx.SetParamValues("commonNamespace", "commonName")
err = appSvc.CreateOrUpdateApplication(echoCtx)
assert.NoError(t, err, "craete application in service")
}
-223
View File
@@ -1,223 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package services
import (
"context"
"fmt"
"net/http"
"strconv"
"time"
"github.com/labstack/echo/v4"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/apiserver/model"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/apis"
)
// CatalogService catalog service
type CatalogService struct {
k8sClient client.Client
}
// NewCatalogService new catalog service
func NewCatalogService(kc client.Client) *CatalogService {
return &CatalogService{
k8sClient: kc,
}
}
// ListCatalogs list method for catalog configmap
func (s *CatalogService) ListCatalogs(c echo.Context) error {
var cmList corev1.ConfigMapList
labels := &metav1.LabelSelector{
MatchLabels: map[string]string{
"catalog": "configdata",
},
}
selector, err := metav1.LabelSelectorAsSelector(labels)
if err != nil {
return err
}
err = s.k8sClient.List(context.Background(), &cmList, &client.ListOptions{
LabelSelector: selector,
})
if err != nil {
return err
}
var catalogList = make([]*model.Catalog, 0, len(cmList.Items))
for i, c := range cmList.Items {
UpdateInt, err := strconv.ParseInt(cmList.Items[i].Data["UpdatedAt"], 10, 64)
if err != nil {
return err
}
catalog := model.Catalog{
Name: c.Name,
UpdatedAt: UpdateInt,
Desc: cmList.Items[i].Data["Desc"],
Type: cmList.Items[i].Data["Type"],
URL: cmList.Items[i].Data["Url"],
Token: cmList.Items[i].Data["Token"],
}
catalogList = append(catalogList, &catalog)
}
return c.JSON(http.StatusOK, apis.CatalogListResponse{Catalogs: catalogList})
}
// GetCatalog get method for catalog configmap
func (s *CatalogService) GetCatalog(c echo.Context) error {
catalogName := c.Param("catalogName")
var cm corev1.ConfigMap
err := s.k8sClient.Get(context.Background(), client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: catalogName}, &cm)
if err != nil {
return c.JSON(http.StatusInternalServerError, fmt.Sprintf("get configMap for %s failed %s", catalogName, err.Error()))
}
UpdatedInt, err := strconv.ParseInt(cm.Data["UpdatedAt"], 10, 64)
if err != nil {
return c.JSON(http.StatusInternalServerError, fmt.Errorf("unable to resolve update parameter in %s: %w ", catalogName, err))
}
var catalog = model.Catalog{
Name: catalogName,
Desc: cm.Data["Desc"],
UpdatedAt: UpdatedInt,
Type: cm.Data["Type"],
URL: cm.Data["Url"],
Token: cm.Data["Token"],
}
return c.JSON(http.StatusOK, apis.CatalogResponse{Catalog: &catalog})
}
// AddCatalog add method for catalog configmap
func (s *CatalogService) AddCatalog(c echo.Context) error {
catalogReq := new(apis.CatalogRequest)
if err := c.Bind(catalogReq); err != nil {
return err
}
exist, err := s.checkCatalogExist(catalogReq.Name)
if err != nil {
return err
}
if exist {
return c.JSON(http.StatusInternalServerError, fmt.Sprintf("catalog %s exist", catalogReq.Name))
}
var cm *corev1.ConfigMap
configdata := map[string]string{
"Name": catalogReq.Name,
"Desc": catalogReq.Desc,
"UpdatedAt": fmt.Sprintf("%d", time.Now().UnixNano()),
}
label := map[string]string{
"catalog": "configdata",
}
cm = toConfigMap(catalogReq.Name, types.DefaultKubeVelaNS, label, configdata)
err = s.k8sClient.Create(context.Background(), cm)
if err != nil {
return fmt.Errorf("unable to create configmap for %s : %w ", catalogReq.Name, err)
}
catalog := convertToCatalog(catalogReq)
return c.JSON(http.StatusCreated, apis.CatalogResponse{Catalog: &catalog})
}
// UpdateCatalog update method for catalog configmap
func (s *CatalogService) UpdateCatalog(c echo.Context) error {
catalogReq := new(apis.CatalogRequest)
if err := c.Bind(catalogReq); err != nil {
return err
}
catalog := convertToCatalog(catalogReq)
configdata := map[string]string{
"Name": catalogReq.Name,
"Desc": catalogReq.Desc,
"UpdatedAt": time.Now().String(),
}
label := map[string]string{
"catalog": "configdata",
}
cm := toConfigMap(catalogReq.Name, types.DefaultKubeVelaNS, label, configdata)
err := s.k8sClient.Update(context.Background(), cm)
if err != nil {
return fmt.Errorf("unable to update configmap for %s : %w ", catalogReq.Name, err)
}
return c.JSON(http.StatusOK, apis.CatalogResponse{Catalog: &catalog})
}
// DelCatalog delete method for catalog configmap
func (s *CatalogService) DelCatalog(c echo.Context) error {
catalogName := c.Param("catalogName")
var cm corev1.ConfigMap
cm.SetName(catalogName)
cm.SetNamespace(types.DefaultKubeVelaNS)
if err := s.k8sClient.Delete(context.Background(), &cm); err != nil {
return c.JSON(http.StatusInternalServerError, false)
}
return c.JSON(http.StatusOK, true)
}
// checkCatalogExist check whether catalog exist with name
func (s *CatalogService) checkCatalogExist(catalogName string) (bool, error) {
var cm corev1.ConfigMap
err := s.k8sClient.Get(context.Background(), client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: catalogName}, &cm)
if err != nil {
if apierrors.IsNotFound(err) { // not found
return false, nil
}
// other error
return false, err
}
// found
return true, nil
}
// convertToCatalog get catalog model from request
func convertToCatalog(catalogReq *apis.CatalogRequest) model.Catalog {
return model.Catalog{
Name: catalogReq.Name,
Desc: catalogReq.Desc,
UpdatedAt: time.Now().Unix(),
Type: catalogReq.Type,
URL: catalogReq.URL,
Token: catalogReq.Token,
}
}
func toConfigMap(name, namespace string, label map[string]string, configData map[string]string) *corev1.ConfigMap {
var cm = corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
}
cm.SetName(name)
cm.SetNamespace(namespace)
cm.SetLabels(label)
cm.Data = configData
return &cm
}
@@ -1,80 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package services
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"github.com/labstack/echo/v4"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/apis"
)
var _ = Describe("Test Catalog Service", func() {
var catalogService *CatalogService
BeforeEach(func() {
catalogService = NewCatalogService(k8sClient)
})
AfterEach(func() {
})
It("should add catalog successfully", func() {
e := echo.New()
cr := &apis.CatalogRequest{
Name: "test",
}
b, err := json.Marshal(cr)
Expect(err).To(BeNil())
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(b))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
Expect(catalogService.AddCatalog(c)).To(BeNil())
checkCatalogResponse(rec, cr, http.StatusCreated)
req = httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec = httptest.NewRecorder()
c = e.NewContext(req, rec)
c.SetPath("/v1/catalogs/:catalogName")
c.SetParamNames("catalogName")
c.SetParamValues(cr.Name)
Expect(catalogService.GetCatalog(c)).To(BeNil())
checkCatalogResponse(rec, cr, http.StatusOK)
})
})
func checkCatalogResponse(rec *httptest.ResponseRecorder, cr *apis.CatalogRequest, httpcode int) {
Expect(rec.Code).To(Equal(httpcode))
get := &apis.CatalogResponse{}
err := json.Unmarshal(rec.Body.Bytes(), get)
Expect(err).To(BeNil())
Expect(get.Catalog.Name).To(Equal(cr.Name))
Expect(get.Catalog.UpdatedAt).NotTo(BeZero())
}
-110
View File
@@ -1,110 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package services
import (
"context"
"math/rand"
"os"
"path/filepath"
"testing"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
oamcorealpha "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
oamstandard "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
// +kubebuilder:scaffold:imports
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
var testScheme = runtime.NewScheme()
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "APIServer Suite")
}
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)))
rand.Seed(time.Now().UnixNano())
By("bootstrapping test environment")
var yamlPath string
if _, set := os.LookupEnv("COMPATIBILITY_TEST"); set {
yamlPath = "../../../../../test/compatibility-test/testdata"
} else {
yamlPath = filepath.Join("../../../../..", "charts", "vela-core", "crds")
}
logf.Log.Info("start application suit test", "yaml_path", yamlPath)
testEnv = &envtest.Environment{
ControlPlaneStartTimeout: time.Minute,
ControlPlaneStopTimeout: time.Minute,
UseExistingCluster: pointer.BoolPtr(false),
CRDDirectoryPaths: []string{yamlPath, "./testdata/crds/terraform.core.oam.dev_configurations.yaml"},
}
var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
err = oamcorealpha.SchemeBuilder.AddToScheme(testScheme)
Expect(err).NotTo(HaveOccurred())
err = oamstandard.SchemeBuilder.AddToScheme(testScheme)
Expect(err).NotTo(HaveOccurred())
err = oamcore.SchemeBuilder.AddToScheme(testScheme)
Expect(err).NotTo(HaveOccurred())
err = clientgoscheme.AddToScheme(testScheme)
Expect(err).NotTo(HaveOccurred())
crdv1.AddToScheme(testScheme)
// +kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: testScheme})
Expect(err).ToNot(HaveOccurred())
Expect(k8sClient).ToNot(BeNil())
definitonNs := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}}
Expect(k8sClient.Create(context.Background(), definitonNs.DeepCopy())).Should(BeNil())
})
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
})
@@ -0,0 +1,42 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package usecase
import (
"context"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
// ClusterUsecase cluster manage
type ClusterUsecase interface {
CreateKubeCluster(context.Context, apis.CreateClusterRequest) (*apis.ClusterBase, error)
}
type clusterUsecaseImpl struct {
ds datastore.DataStore
}
// NewClusterUsecase new cluster usecase
func NewClusterUsecase(ds datastore.DataStore) ClusterUsecase {
return &clusterUsecaseImpl{ds: ds}
}
func (c *clusterUsecaseImpl) CreateKubeCluster(context.Context, apis.CreateClusterRequest) (*apis.ClusterBase, error) {
return nil, nil
}
+67
View File
@@ -0,0 +1,67 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package bcode
import (
"errors"
"fmt"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-playground/validator/v10"
"github.com/oam-dev/kubevela/pkg/apiserver/log"
)
// Bcode business error code
type Bcode struct {
HTTPCode int32 `json:"-"`
BusinessCode int32
Message string
}
func (b *Bcode) Error() string {
return fmt.Sprintf("HTTPCode:%d BusinessCode:%d Message:%s", b.HTTPCode, b.BusinessCode, b.Message)
}
// ReturnError Unified handling of all types of errors, generating a standard return structure.
func ReturnError(req *restful.Request, res *restful.Response, err error) {
var bcode *Bcode
if errors.As(err, &bcode) {
if err := res.WriteEntity(err); err != nil {
log.Logger.Error("write entity failure %s", err.Error())
}
return
}
var restfulerr *restful.ServiceError
if errors.As(err, restfulerr) {
if err := res.WriteEntity(Bcode{HTTPCode: int32(restfulerr.Code), BusinessCode: int32(restfulerr.Code), Message: restfulerr.Message}); err != nil {
log.Logger.Error("write entity failure %s", err.Error())
}
return
}
var validErr *validator.ValidationErrors
if errors.As(err, validErr) {
if err := res.WriteEntity(Bcode{HTTPCode: 400, BusinessCode: 400, Message: err.Error()}); err != nil {
log.Logger.Error("write entity failure %s", err.Error())
}
return
}
log.Logger.Errorf("Business exceptions, message %s, path:%s method:%s", err.Error(), req.Request.URL, req.Request.Method)
if err := res.WriteEntity(Bcode{HTTPCode: 500, BusinessCode: 500, Message: err.Error()}); err != nil {
log.Logger.Error("write entity failure %s", err.Error())
}
}
@@ -0,0 +1,90 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
type applicationWebService struct {
}
func (c *applicationWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/applications").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for application manage")
tags := []string{"application"}
ws.Route(ws.GET("/").To(noop).
Doc("list all applications").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("query", "Fuzzy search based on name or description").DataType("string")).
Param(ws.QueryParameter("namespace", "Namespace-based search").DataType("string")).
Param(ws.QueryParameter("cluster", "Cluster-based search").DataType("string")).
Writes(apis.ListApplicationResponse{}))
ws.Route(ws.POST("/").To(noop).
Doc("create one application").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(apis.CreateApplicationRequest{}).
Writes(apis.ApplicationBase{}))
ws.Route(ws.DELETE("/{name}").To(noop).
Doc("delete one application").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
Writes(apis.ApplicationBase{}))
ws.Route(ws.GET("/{name}").To(noop).
Doc("detail one application").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
Writes(apis.DetailApplicationResponse{}))
ws.Route(ws.POST("/{name}/template").To(noop).
Doc("create one application template").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
Reads(apis.CreateApplicationTemplateRequest{}).
Writes(apis.ApplicationTemplateBase{}))
ws.Route(ws.POST("/{name}/deploy").To(noop).
Doc("deploy or update the application").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
Writes(apis.ApplicationBase{}))
ws.Route(ws.GET("/{name}/components").To(noop).
Doc("gets the component topology of the application").
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(apis.ComponentListResponse{}))
ws.Route(ws.POST("/{name}/components").To(noop).
Doc("create component for application").
Param(ws.PathParameter("name", "identifier of the application").DataType("string")).
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(apis.CreateComponentRequest{}).
Writes(apis.ComponentBase{}))
return ws
}
+45
View File
@@ -0,0 +1,45 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
type catalogWebService struct {
}
func (c *catalogWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path("/v1/catalogs").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for cluster manage")
tags := []string{"cluster"}
ws.Route(ws.GET("/").To(noop).
Doc("list all clusters").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("query", "Fuzzy search based on name or description").DataType("string")).
Writes(apis.ListClusterResponse{}).Do(returns200, returns500))
return ws
}
+97
View File
@@ -0,0 +1,97 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
)
type clusterWebService struct {
clusterUsecase usecase.ClusterUsecase
}
func (c *clusterWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/clusters").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for cluster manage")
tags := []string{"cluster"}
ws.Route(ws.GET("/").To(noop).
Doc("list all clusters").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("query", "Fuzzy search based on name or description").DataType("string")).
Writes(apis.ListClusterResponse{}).Do(returns200, returns500))
ws.Route(ws.POST("/").To(c.createKubeCluster).
Doc("create cluster").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(&apis.CreateClusterRequest{}).
Writes(apis.ClusterBase{}))
ws.Route(ws.GET("/{clusterName}").To(noop).
Doc("detail cluster info").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("clusterName", "identifier of the cluster").DataType("string")).
Writes(apis.DetailClusterResponse{}))
// Do not implement this dimension for now.
// ws.Route(ws.GET("/{clusterName}/addons").To(noop).
// Doc("list cluster addons info").
// Metadata(restfulspec.KeyOpenAPITags, tags).
// Param(ws.PathParameter("clusterName", "identifier of the cluster").DataType("string")).
// Writes(apis.ListClusterAddonResponse{}))
// ws.Route(ws.POST("/{clusterName}/addons").To(noop).
// Doc("add addon for the cluster").
// Metadata(restfulspec.KeyOpenAPITags, tags).
// Param(ws.PathParameter("clusterName", "identifier of the cluster").DataType("string")).
// Writes(apis.DeatilClusterAddonResponse{}).Returns(200, "", apis.DeatilClusterAddonResponse{}))
return ws
}
func (c *clusterWebService) createKubeCluster(req *restful.Request, res *restful.Response) {
// Verify the validity of parameters
var createReq apis.CreateClusterRequest
if err := req.ReadEntity(&createReq); err != nil {
bcode.ReturnError(req, res, err)
return
}
if err := validate.Struct(&createReq); err != nil {
bcode.ReturnError(req, res, err)
return
}
// Call the usecase layer code
clusterBase, err := c.clusterUsecase.CreateKubeCluster(req.Request.Context(), createReq)
if err != nil {
bcode.ReturnError(req, res, err)
return
}
// Write back response data
if err := res.WriteEntity(clusterBase); err != nil {
bcode.ReturnError(req, res, err)
return
}
}
@@ -0,0 +1,45 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
type componentDefinitionWebservice struct {
}
func (c *componentDefinitionWebservice) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/componentdefinitions").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for componentdefinition manage")
tags := []string{"componentdefinition"}
ws.Route(ws.GET("/").To(noop).
Doc("list all componentdefinition").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("appName", "if specified, query the componentdefinition supported by the cluster where the application resides.").DataType("string")).
Param(ws.QueryParameter("clusterName", "if specified, query the componentdefinition supported by the cluster.").DataType("string")).
Writes(apis.ListComponentDefinitionResponse{}))
return ws
}
@@ -0,0 +1,76 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
type namespaceWebService struct {
}
func (c *namespaceWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/namespaces").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for namespace manage")
tags := []string{"namespace"}
ws.Route(ws.GET("/").To(noop).
Doc("list all namespaces").
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(apis.ListNamespaceResponse{}))
ws.Route(ws.POST("/").To(noop).
Doc("create namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Reads(apis.CreateNamespaceRequest{}).
Writes(apis.NamesapceDetailResponse{}))
ws.Route(ws.GET("/{namespace}").To(noop).
Doc("get one namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Writes(apis.NamesapceDetailResponse{}))
// Compatible with historical apis
ws.Route(ws.GET("/{namespace}/applications/:appname").To(noop).
Doc("get the specified oam application in the specified namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Param(ws.PathParameter("appname", "identifier of the oam application").DataType("string")).
Writes(apis.ApplicationResponse{}))
ws.Route(ws.POST("/{namespace}/applications/:appname").To(noop).
Doc("create or update oam application in the specified namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Param(ws.PathParameter("appname", "identifier of the oam application").DataType("string")).
Reads(apis.ApplicationRequest{}))
ws.Route(ws.DELETE("/{namespace}/applications/:appname").To(noop).
Doc("create or update oam application in the specified namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Param(ws.PathParameter("appname", "identifier of the oam application").DataType("string")))
return ws
}
@@ -0,0 +1,58 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
)
type oamApplicationWebService struct {
}
func (c *oamApplicationWebService) GetWebService() *restful.WebService {
ws := new(restful.WebService)
ws.Path("/v1").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML).
Doc("api for oam application manage")
tags := []string{"oam"}
ws.Route(ws.GET("/{namespace}/applications/:appname").To(noop).
Doc("get the specified oam application in the specified namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Param(ws.PathParameter("appname", "identifier of the oam application").DataType("string")).
Writes(apis.ApplicationResponse{}))
ws.Route(ws.POST("/{namespace}/applications/{appname}").To(noop).
Doc("create or update oam application in the specified namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Param(ws.PathParameter("appname", "identifier of the oam application").DataType("string")).
Reads(apis.ApplicationRequest{}))
ws.Route(ws.DELETE("/{namespace}/applications/:appname").To(noop).
Doc("create or update oam application in the specified namespace").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.PathParameter("namespace", "identifier of the namespace").DataType("string")).
Param(ws.PathParameter("appname", "identifier of the oam application").DataType("string")))
return ws
}
@@ -0,0 +1,67 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package webservice
import (
"context"
"net/http"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-playground/validator/v10"
)
// versionPrefix API version prefix.
var versionPrefix = "/api/v1"
var validate = validator.New()
// WebService webservice interface
type WebService interface {
GetWebService() *restful.WebService
}
var registedWebService []WebService
// RegistWebService regist webservice
func RegistWebService(ws WebService) {
registedWebService = append(registedWebService, ws)
}
// GetRegistedWebService return registedWebService
func GetRegistedWebService() []WebService {
return registedWebService
}
func noop(req *restful.Request, resp *restful.Response) {}
func returns200(b *restful.RouteBuilder) {
b.Returns(http.StatusOK, "OK", map[string]string{"status": "ok"})
}
func returns500(b *restful.RouteBuilder) {
b.Returns(http.StatusInternalServerError, "Bummer, something went wrong", nil)
}
// Init init all webservice, pass in the required parameter object.
func Init(ctx context.Context) {
RegistWebService(&clusterWebService{})
RegistWebService(&applicationWebService{})
RegistWebService(&namespaceWebService{})
RegistWebService(&componentDefinitionWebservice{})
RegistWebService(&catalogWebService{})
RegistWebService(&oamApplicationWebService{})
}