Dragonfly2
273 строки · 8.4 Кб
1/*
2* Copyright 2020 The Dragonfly Authors
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17package router
18
19import (
20"net/http"
21"time"
22
23"github.com/casbin/casbin/v2"
24"github.com/gin-contrib/gzip"
25"github.com/gin-contrib/static"
26ginzap "github.com/gin-contrib/zap"
27"github.com/gin-gonic/gin"
28ginprometheus "github.com/mcuadros/go-gin-prometheus"
29swaggerFiles "github.com/swaggo/files"
30ginSwagger "github.com/swaggo/gin-swagger"
31"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
32
33logger "d7y.io/dragonfly/v2/internal/dflog"
34"d7y.io/dragonfly/v2/manager/config"
35"d7y.io/dragonfly/v2/manager/database"
36"d7y.io/dragonfly/v2/manager/handlers"
37"d7y.io/dragonfly/v2/manager/middlewares"
38"d7y.io/dragonfly/v2/manager/service"
39)
40
41const (
42PrometheusSubsystemName = "dragonfly_manager"
43OtelServiceName = "dragonfly-manager"
44)
45
46func Init(cfg *config.Config, logDir string, service service.Service, database *database.Database, enforcer *casbin.Enforcer, assets static.ServeFileSystem) (*gin.Engine, error) {
47// Set mode.
48if !cfg.Verbose {
49gin.SetMode(gin.ReleaseMode)
50}
51
52r := gin.New()
53h := handlers.New(service)
54
55// Prometheus metrics.
56p := ginprometheus.NewPrometheus(PrometheusSubsystemName)
57// URL removes query string.
58// Prometheus metrics need to reduce label,
59// refer to https://prometheus.io/docs/practices/instrumentation/#do-not-overuse-labels.
60p.ReqCntURLLabelMappingFn = func(c *gin.Context) string {
61return c.Request.URL.Path
62}
63p.Use(r)
64
65// Opentelemetry.
66if cfg.Options.Telemetry.Jaeger != "" {
67r.Use(otelgin.Middleware(OtelServiceName))
68}
69
70// Gin middleware.
71r.Use(gin.Recovery())
72r.Use(ginzap.Ginzap(logger.GinLogger.Desugar(), time.RFC3339, true))
73r.Use(ginzap.RecoveryWithZap(logger.GinLogger.Desugar(), true))
74
75// Error middleware.
76r.Use(middlewares.Error())
77
78// CORS middleware.
79r.Use(middlewares.CORS())
80
81// gzip middleware.
82r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedExtensions([]string{".js", ".css"})))
83
84// RBAC middleware.
85rbac := middlewares.RBAC(enforcer)
86jwt, err := middlewares.Jwt(cfg.Auth.JWT, service)
87if err != nil {
88return nil, err
89}
90
91// Personal access token middleware.
92personalAccessToken := middlewares.PersonalAccessToken(database.DB)
93
94// Manager view.
95r.Use(static.Serve("/", assets))
96
97// API router.
98apiv1 := r.Group("/api/v1")
99
100// User.
101u := apiv1.Group("/users")
102u.PATCH(":id", jwt.MiddlewareFunc(), rbac, h.UpdateUser)
103u.GET(":id", jwt.MiddlewareFunc(), rbac, h.GetUser)
104u.GET("", jwt.MiddlewareFunc(), rbac, h.GetUsers)
105u.POST("signin", jwt.LoginHandler)
106u.POST("signout", jwt.LogoutHandler)
107u.POST("signup", h.SignUp)
108u.GET("signin/:name", h.OauthSignin)
109u.GET("signin/:name/callback", h.OauthSigninCallback(jwt))
110u.POST("refresh_token", jwt.RefreshHandler)
111u.POST(":id/reset_password", h.ResetPassword)
112u.GET(":id/roles", jwt.MiddlewareFunc(), rbac, h.GetRolesForUser)
113u.PUT(":id/roles/:role", jwt.MiddlewareFunc(), rbac, h.AddRoleToUser)
114u.DELETE(":id/roles/:role", jwt.MiddlewareFunc(), rbac, h.DeleteRoleForUser)
115
116// Role.
117re := apiv1.Group("/roles", jwt.MiddlewareFunc(), rbac)
118re.POST("", h.CreateRole)
119re.DELETE(":role", h.DestroyRole)
120re.GET(":role", h.GetRole)
121re.GET("", h.GetRoles)
122re.POST(":role/permissions", h.AddPermissionForRole)
123re.DELETE(":role/permissions", h.DeletePermissionForRole)
124
125// Permission.
126pm := apiv1.Group("/permissions", jwt.MiddlewareFunc(), rbac)
127pm.GET("", h.GetPermissions(r))
128
129// Oauth.
130oa := apiv1.Group("/oauth")
131oa.POST("", jwt.MiddlewareFunc(), rbac, h.CreateOauth)
132oa.DELETE(":id", jwt.MiddlewareFunc(), rbac, h.DestroyOauth)
133oa.PATCH(":id", jwt.MiddlewareFunc(), rbac, h.UpdateOauth)
134oa.GET(":id", h.GetOauth)
135oa.GET("", h.GetOauths)
136
137// Cluster.
138c := apiv1.Group("/clusters", jwt.MiddlewareFunc(), rbac)
139c.POST("", h.CreateCluster)
140c.DELETE(":id", h.DestroyCluster)
141c.PATCH(":id", h.UpdateCluster)
142c.GET(":id", h.GetCluster)
143c.GET("", h.GetClusters)
144
145// Scheduler Cluster.
146sc := apiv1.Group("/scheduler-clusters", jwt.MiddlewareFunc(), rbac)
147sc.POST("", h.CreateSchedulerCluster)
148sc.DELETE(":id", h.DestroySchedulerCluster)
149sc.PATCH(":id", h.UpdateSchedulerCluster)
150sc.GET(":id", h.GetSchedulerCluster)
151sc.GET("", h.GetSchedulerClusters)
152sc.PUT(":id/schedulers/:scheduler_id", h.AddSchedulerToSchedulerCluster)
153
154// Scheduler.
155s := apiv1.Group("/schedulers", jwt.MiddlewareFunc(), rbac)
156s.POST("", h.CreateScheduler)
157s.DELETE(":id", h.DestroyScheduler)
158s.PATCH(":id", h.UpdateScheduler)
159s.GET(":id", h.GetScheduler)
160s.GET("", h.GetSchedulers)
161
162// Seed Peer Cluster.
163spc := apiv1.Group("/seed-peer-clusters", jwt.MiddlewareFunc(), rbac)
164spc.POST("", h.CreateSeedPeerCluster)
165spc.DELETE(":id", h.DestroySeedPeerCluster)
166spc.PATCH(":id", h.UpdateSeedPeerCluster)
167spc.GET(":id", h.GetSeedPeerCluster)
168spc.GET("", h.GetSeedPeerClusters)
169spc.PUT(":id/seed-peers/:seed_peer_id", h.AddSeedPeerToSeedPeerCluster)
170spc.PUT(":id/scheduler-clusters/:scheduler_cluster_id", h.AddSchedulerClusterToSeedPeerCluster)
171
172// Seed Peer.
173sp := apiv1.Group("/seed-peers", jwt.MiddlewareFunc(), rbac)
174sp.POST("", h.CreateSeedPeer)
175sp.DELETE(":id", h.DestroySeedPeer)
176sp.PATCH(":id", h.UpdateSeedPeer)
177sp.GET(":id", h.GetSeedPeer)
178sp.GET("", h.GetSeedPeers)
179
180// Peer.
181peer := apiv1.Group("/peers", jwt.MiddlewareFunc(), rbac)
182peer.POST("", h.CreatePeer)
183peer.DELETE(":id", h.DestroyPeer)
184peer.GET(":id", h.GetPeer)
185peer.GET("", h.GetPeers)
186
187// Bucket.
188bucket := apiv1.Group("/buckets", jwt.MiddlewareFunc(), rbac)
189bucket.POST("", h.CreateBucket)
190bucket.DELETE(":id", h.DestroyBucket)
191bucket.GET(":id", h.GetBucket)
192bucket.GET("", h.GetBuckets)
193
194// Config.
195config := apiv1.Group("/configs")
196config.POST("", jwt.MiddlewareFunc(), rbac, h.CreateConfig)
197config.DELETE(":id", jwt.MiddlewareFunc(), rbac, h.DestroyConfig)
198config.PATCH(":id", jwt.MiddlewareFunc(), rbac, h.UpdateConfig)
199config.GET(":id", jwt.MiddlewareFunc(), rbac, h.GetConfig)
200config.GET("", h.GetConfigs)
201
202// TODO Add auth to the following routes and fix the tests.
203// Job.
204job := apiv1.Group("/jobs")
205job.POST("", h.CreateJob)
206job.DELETE(":id", h.DestroyJob)
207job.PATCH(":id", h.UpdateJob)
208job.GET(":id", h.GetJob)
209job.GET("", h.GetJobs)
210
211// Application.
212cs := apiv1.Group("/applications", jwt.MiddlewareFunc(), rbac)
213cs.POST("", h.CreateApplication)
214cs.DELETE(":id", h.DestroyApplication)
215cs.PATCH(":id", h.UpdateApplication)
216cs.GET(":id", h.GetApplication)
217cs.GET("", h.GetApplications)
218
219// Model.
220model := apiv1.Group("/models", jwt.MiddlewareFunc(), rbac)
221model.DELETE(":id", h.DestroyModel)
222model.PATCH(":id", h.UpdateModel)
223model.GET(":id", h.GetModel)
224model.GET("", h.GetModels)
225
226// Personal Access Token.
227pat := apiv1.Group("/personal-access-tokens", jwt.MiddlewareFunc(), rbac)
228pat.POST("", h.CreatePersonalAccessToken)
229pat.DELETE(":id", h.DestroyPersonalAccessToken)
230pat.PATCH(":id", h.UpdatePersonalAccessToken)
231pat.GET(":id", h.GetPersonalAccessToken)
232pat.GET("", h.GetPersonalAccessTokens)
233
234// Open API router.
235oapiv1 := r.Group("/oapi/v1")
236
237// Job.
238ojob := oapiv1.Group("/jobs", personalAccessToken)
239ojob.POST("", h.CreateJob)
240ojob.DELETE(":id", h.DestroyJob)
241ojob.PATCH(":id", h.UpdateJob)
242ojob.GET(":id", h.GetJob)
243ojob.GET("", h.GetJobs)
244
245// Cluster.
246oc := oapiv1.Group("/clusters", personalAccessToken)
247oc.POST("", h.CreateCluster)
248oc.DELETE(":id", h.DestroyCluster)
249oc.PATCH(":id", h.UpdateCluster)
250oc.GET(":id", h.GetCluster)
251oc.GET("", h.GetClusters)
252
253// TODO Remove this api.
254// Compatible with the V1 preheat.
255pv1 := r.Group("/preheats")
256r.GET("_ping", h.GetHealth)
257pv1.POST("", h.CreateV1Preheat)
258pv1.GET(":id", h.GetV1Preheat)
259
260// Health Check.
261r.GET("/healthy", h.GetHealth)
262
263// Swagger.
264apiSeagger := ginSwagger.URL("/swagger/doc.json")
265r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, apiSeagger))
266
267// Fallback to manager view.
268r.NoRoute(func(c *gin.Context) {
269c.Redirect(http.StatusMovedPermanently, "/")
270})
271
272return r, nil
273}
274