feat(strategy): add option to show instances details

Closes #77
This commit is contained in:
Alexis Couvreur
2022-11-10 15:07:33 +00:00
parent 77b2611328
commit 546b378416
15 changed files with 107 additions and 2 deletions

View File

@@ -11,11 +11,12 @@ testData:
names: whoami,nginx # Comma separated names of containers/services/deployments etc.
sessionDuration: 1m # The session duration after which containers/services/deployments instances are shutdown
# You can only use one strategy at a time
# To do so, only declare `dynamic` or `blockin`
# To do so, only declare `dynamic` or `blocking`
# Dynamic strategy, provides the waiting webui
dynamic:
displayName: My Title # (Optional) Defaults to the middleware name
showDetails: true # (Optional) Set to true or false to show details specifcally for this middleware, unset to use Sablier server defaults
theme: hacker-terminal # (Optional) The theme to use
refreshFrequency: 5s # (Optional) The loading page refresh frequency

View File

@@ -25,6 +25,7 @@ type RenderOptionsInstanceState struct {
type RenderOptions struct {
DisplayName string
ShowDetails bool
InstanceStates []RenderOptionsInstanceState
SessionDuration time.Duration
RefreshFrequency time.Duration
@@ -61,9 +62,15 @@ func Render(options RenderOptions, writer io.Writer) error {
return err
}
instanceStates := []RenderOptionsInstanceState{}
if options.ShowDetails {
instanceStates = options.InstanceStates
}
return tpl.Execute(writer, TemplateValues{
DisplayName: options.DisplayName,
InstanceStates: options.InstanceStates,
InstanceStates: instanceStates,
SessionDuration: humanizeDuration(options.SessionDuration),
RefreshFrequency: fmt.Sprintf("%d", int64(options.RefreshFrequency.Seconds())),
Version: options.Version,

View File

@@ -242,6 +242,38 @@ func TestRenderContent(t *testing.T) {
},
wantContent: "<meta http-equiv=\"refresh\" content=\"10\" />",
},
{
name: "details is rendered",
args: args{
options: RenderOptions{
DisplayName: "Test",
ShowDetails: true,
InstanceStates: instanceStates,
Theme: "ghost",
SessionDuration: 10 * time.Minute,
RefreshFrequency: 10 * time.Second,
CustomThemes: nil,
Version: "v0.0.0",
},
},
wantContent: "started (4/4)",
},
{
name: "details is not rendered",
args: args{
options: RenderOptions{
DisplayName: "Test",
ShowDetails: false,
InstanceStates: instanceStates,
Theme: "ghost",
SessionDuration: 10 * time.Minute,
RefreshFrequency: 10 * time.Second,
CustomThemes: nil,
Version: "v0.0.0",
},
},
wantContent: "<table></table>",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -6,6 +6,7 @@ import (
type DynamicRequest struct {
Names []string `form:"names" binding:"required"`
ShowDetails bool `form:"show_details"`
DisplayName string `form:"display_name"`
Theme string `form:"theme"`
SessionDuration time.Duration `form:"session_duration" binding:"required"`

View File

@@ -49,6 +49,7 @@ func NewServeStrategy(sessionsManager sessions.Manager, conf config.Strategy) *S
func (s *ServeStrategy) ServeDynamic(c *gin.Context) {
request := models.DynamicRequest{
Theme: s.StrategyConfig.Dynamic.DefaultTheme,
ShowDetails: s.StrategyConfig.Dynamic.ShowDetailsByDefault,
RefreshFrequency: s.StrategyConfig.Dynamic.DefaultRefreshFrequency,
}
@@ -67,6 +68,7 @@ func (s *ServeStrategy) ServeDynamic(c *gin.Context) {
renderOptions := pages.RenderOptions{
DisplayName: request.DisplayName,
ShowDetails: request.ShowDetails,
SessionDuration: request.SessionDuration,
Theme: request.Theme,
CustomThemes: s.customThemesFS,

View File

@@ -66,6 +66,8 @@ It provides an integrations with multiple reverse proxies and different loading
viper.BindPFlag("strategy.dynamic.custom-themes-path", startCmd.Flags().Lookup("strategy.dynamic.custom-themes-path"))
startCmd.Flags().StringVar(&conf.Strategy.Dynamic.DefaultTheme, "strategy.dynamic.default-theme", "hacker-terminal", "Default theme used for dynamic strategy")
viper.BindPFlag("strategy.dynamic.default-theme", startCmd.Flags().Lookup("strategy.dynamic.default-theme"))
startCmd.Flags().BoolVar(&conf.Strategy.Dynamic.ShowDetailsByDefault, "strategy.dynamic.show-details-by-default", true, "Show the loading instances details by default")
viper.BindPFlag("strategy.dynamic.show-details-by-default", startCmd.Flags().Lookup("strategy.dynamic.show-details-by-default"))
startCmd.Flags().DurationVar(&conf.Strategy.Dynamic.DefaultRefreshFrequency, "strategy.dynamic.default-refresh-frequency", 5*time.Second, "Default refresh frequency in the HTML page for dynamic strategy")
viper.BindPFlag("strategy.dynamic.default-refresh-frequency", startCmd.Flags().Lookup("strategy.dynamic.default-refresh-frequency"))
startCmd.Flags().DurationVar(&conf.Strategy.Blocking.DefaultTimeout, "strategy.blocking.default-timeout", 1*time.Minute, "Default timeout used for blocking strategy")

View File

@@ -106,6 +106,8 @@ func TestPrecedence(t *testing.T) {
"--sessions.expiration-interval", "3h",
"--logging.level", "info",
"--strategy.dynamic.custom-themes-path", "/tmp/cli/themes",
// Must use `=` see https://github.com/spf13/cobra/issues/613
"--strategy.dynamic.show-details-by-default=false",
"--strategy.dynamic.default-theme", "cli",
"--strategy.dynamic.default-refresh-frequency", "3h",
"--strategy.blocking.default-timeout", "3h",

View File

@@ -6,6 +6,7 @@ SESSIONS_DEFAULT_DURATION=2h
SESSIONS_EXPIRATION_INTERVAL=2h
LOGGING_LEVEL=debug
STRATEGY_DYNAMIC_CUSTOM_THEMES_PATH=/tmp/envvar/themes
STRATEGY_SHOW_DETAILS_BY_DEFAULT=false
STRATEGY_DYNAMIC_DEFAULT_THEME=envvar
STRATEGY_DYNAMIC_DEFAULT_REFRESH_FREQUENCY=2h
STRATEGY_BLOCKING_DEFAULT_TIMEOUT=2h

View File

@@ -13,6 +13,7 @@ logging:
strategy:
dynamic:
custom-themes-path: /tmp/configfile/themes
show-details-by-default: false
default-theme: configfile
default-refresh-frequency: 1h
blocking:

View File

@@ -19,6 +19,7 @@
"Strategy": {
"Dynamic": {
"CustomThemesPath": "/tmp/cli/themes",
"ShowDetailsByDefault": false,
"DefaultTheme": "cli",
"DefaultRefreshFrequency": 10800000000000
},

View File

@@ -19,6 +19,7 @@
"Strategy": {
"Dynamic": {
"CustomThemesPath": "/tmp/envvar/themes",
"ShowDetailsByDefault": false,
"DefaultTheme": "envvar",
"DefaultRefreshFrequency": 7200000000000
},

View File

@@ -19,6 +19,7 @@
"Strategy": {
"Dynamic": {
"CustomThemesPath": "/tmp/configfile/themes",
"ShowDetailsByDefault": false,
"DefaultTheme": "configfile",
"DefaultRefreshFrequency": 3600000000000
},

View File

@@ -4,6 +4,7 @@ import "time"
type DynamicStrategy struct {
CustomThemesPath string `mapstructure:"CUSTOM_THEMES_PATH" yaml:"customThemesPath"`
ShowDetailsByDefault bool `mapstructure:"SHOW_DETAILS_BY_DEFAULT" yaml:"showDetailsByDefault"`
DefaultTheme string `mapstructure:"DEFAULT_THEME" yaml:"defaultTheme" default:"hacker-terminal"`
DefaultRefreshFrequency time.Duration `mapstructure:"DEFAULT_REFRESH_FREQUENCY" yaml:"defaultRefreshFrequency" default:"5s"`
}
@@ -27,6 +28,7 @@ func NewStrategyConfig() Strategy {
func newDynamicStrategy() DynamicStrategy {
return DynamicStrategy{
DefaultTheme: "hacker-terminal",
ShowDetailsByDefault: true,
DefaultRefreshFrequency: 5 * time.Second,
}
}

View File

@@ -3,12 +3,14 @@ package traefik
import (
"fmt"
"net/http"
"strconv"
"strings"
"time"
)
type DynamicConfiguration struct {
DisplayName string `yaml:"displayname"`
ShowDetails *bool `yaml:"showDetails"`
Theme string `yaml:"theme"`
RefreshFrequency string `yaml:"refreshFrequency"`
}
@@ -110,6 +112,10 @@ func (c *Config) buildDynamicRequest(middlewareName string) (*http.Request, erro
q.Add("refresh_frequency", c.Dynamic.RefreshFrequency)
}
if c.Dynamic.ShowDetails != nil {
q.Add("show_details", strconv.FormatBool(*c.Dynamic.ShowDetails))
}
request.URL.RawQuery = q.Encode()
return request, nil

View File

@@ -9,6 +9,9 @@ import (
"github.com/acouvreur/sablier/plugins/traefik"
)
var fals bool = false
var tru bool = true
func TestConfig_BuildRequest(t *testing.T) {
type fields struct {
SablierURL string
@@ -98,6 +101,48 @@ func TestConfig_BuildRequest(t *testing.T) {
want: nil,
wantErr: true,
},
{
name: "dynamic session with show details to true",
fields: fields{
SablierURL: "http://sablier:10000",
Names: "nginx , apache",
SessionDuration: "1m",
Dynamic: &traefik.DynamicConfiguration{
ShowDetails: &tru,
RefreshFrequency: "1m",
},
},
want: createRequest("GET", "http://sablier:10000/api/strategies/dynamic?display_name=sablier-middleware&names=nginx&names=apache&refresh_frequency=1m&session_duration=1m&show_details=true", nil),
wantErr: false,
},
{
name: "dynamic session with show details to false",
fields: fields{
SablierURL: "http://sablier:10000",
Names: "nginx , apache",
SessionDuration: "1m",
Dynamic: &traefik.DynamicConfiguration{
ShowDetails: &fals,
RefreshFrequency: "1m",
},
},
want: createRequest("GET", "http://sablier:10000/api/strategies/dynamic?display_name=sablier-middleware&names=nginx&names=apache&refresh_frequency=1m&session_duration=1m&show_details=false", nil),
wantErr: false,
},
{
name: "dynamic session without show details set",
fields: fields{
SablierURL: "http://sablier:10000",
Names: "nginx , apache",
SessionDuration: "1m",
Dynamic: &traefik.DynamicConfiguration{
ShowDetails: nil,
RefreshFrequency: "1m",
},
},
want: createRequest("GET", "http://sablier:10000/api/strategies/dynamic?display_name=sablier-middleware&names=nginx&names=apache&refresh_frequency=1m&session_duration=1m", nil),
wantErr: false,
},
{
name: "blocking session with default values",
fields: fields{