...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/apiserver/server.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/apiserver

     1  // Copyright 2020 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package apiserver
    15  
    16  import (
    17  	"fmt"
    18  	"net"
    19  	"net/http"
    20  
    21  	"github.com/gin-contrib/pprof"
    22  	"github.com/gin-gonic/gin"
    23  	"github.com/gin-gonic/gin/binding"
    24  	"github.com/go-playground/validator/v10"
    25  	"go.uber.org/fx"
    26  
    27  	apiutils "github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils"
    28  	"github.com/chaos-mesh/chaos-mesh/pkg/apivalidator"
    29  	config "github.com/chaos-mesh/chaos-mesh/pkg/config/dashboard"
    30  	"github.com/chaos-mesh/chaos-mesh/pkg/swaggerserver"
    31  	"github.com/chaos-mesh/chaos-mesh/pkg/uiserver"
    32  )
    33  
    34  var (
    35  	// Module includes the providers (gin engine and api router) and the registers.
    36  	Module = fx.Options(
    37  		fx.Provide(
    38  			newEngine,
    39  			newAPIRouter,
    40  		),
    41  		handlerModule,
    42  		fx.Invoke(serverRegister),
    43  	)
    44  )
    45  
    46  func serverRegister(r *gin.Engine, conf *config.ChaosDashboardConfig) {
    47  	listenAddr := net.JoinHostPort(conf.ListenHost, fmt.Sprintf("%d", conf.ListenPort))
    48  
    49  	go r.Run(listenAddr)
    50  }
    51  
    52  func newEngine(config *config.ChaosDashboardConfig) *gin.Engine {
    53  	r := gin.Default()
    54  
    55  	// default is "/debug/pprof/"
    56  	pprof.Register(r)
    57  
    58  	r.Use(apiutils.MWHandleErrors())
    59  
    60  	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    61  		v.RegisterValidation("NameValid", apivalidator.NameValid)
    62  		v.RegisterValidation("NamespaceSelectorsValid", apivalidator.NamespaceSelectorsValid)
    63  		v.RegisterValidation("MapSelectorsValid", apivalidator.MapSelectorsValid)
    64  		v.RegisterValidation("RequirementSelectorsValid", apivalidator.RequirementSelectorsValid)
    65  		v.RegisterValidation("PhaseSelectorsValid", apivalidator.PhaseSelectorsValid)
    66  		v.RegisterValidation("CronValid", apivalidator.CronValid)
    67  		v.RegisterValidation("DurationValid", apivalidator.DurationValid)
    68  		v.RegisterValidation("ValueValid", apivalidator.ValueValid)
    69  		v.RegisterValidation("PodsValid", apivalidator.PodsValid)
    70  		v.RegisterValidation("RequiredFieldEqual", apivalidator.RequiredFieldEqualValid, true)
    71  	}
    72  
    73  	ui := uiserver.AssetsFS()
    74  	if ui != nil {
    75  		r.GET("/", func(c *gin.Context) {
    76  			c.FileFromFS("/", ui)
    77  		})
    78  		// `/:foo/*bar` from https://en.wikipedia.org/wiki/Foobar, the name itself has no meaning.
    79  		//
    80  		// This handle just internally redirects all no-exact routes to the root directory of static files because the UI is a single page application and only has one entry (index.html).
    81  		r.GET("/:foo", func(c *gin.Context) {
    82  			c.FileFromFS("/", ui)
    83  		})
    84  		r.GET("/:foo/*bar", func(c *gin.Context) {
    85  			c.FileFromFS("/", ui)
    86  		})
    87  
    88  		renderStatic := func(c *gin.Context) {
    89  			c.FileFromFS(c.Request.URL.Path, ui)
    90  		}
    91  		r.GET("/static/*any", renderStatic)
    92  		r.GET("/favicon.ico", renderStatic)
    93  	} else {
    94  		r.GET("/", func(c *gin.Context) {
    95  			c.String(http.StatusOK, "Dashboard UI is not built. Please run `UI=1 make`.")
    96  		})
    97  	}
    98  
    99  	return r
   100  }
   101  
   102  func newAPIRouter(r *gin.Engine) *gin.RouterGroup {
   103  	api := r.Group("/api")
   104  	{
   105  		api.GET("/swagger/*any", swaggerserver.Handler())
   106  	}
   107  
   108  	return api
   109  }
   110