Skip to content

Commit ff6cd04

Browse files
committed
chore: using exporter-toolkit/web for web config
Signed-off-by: SamYuan1990 <[email protected]>
1 parent 8168279 commit ff6cd04

File tree

5 files changed

+74
-72
lines changed

5 files changed

+74
-72
lines changed

config/config.go

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"time"
1212

1313
"github.com/alecthomas/kingpin/v2"
14+
"github.com/prometheus/exporter-toolkit/web"
15+
"github.com/prometheus/exporter-toolkit/web/kingpinflag"
1416
"gopkg.in/yaml.v3"
1517
"k8s.io/utils/ptr"
1618
)
@@ -39,7 +41,7 @@ type (
3941
} `yaml:"fake-cpu-meter"`
4042
}
4143
Web struct {
42-
Config string `yaml:"configFile"`
44+
Config *web.FlagConfig
4345
}
4446

4547
Monitor struct {
@@ -83,9 +85,9 @@ type (
8385
Monitor Monitor `yaml:"monitor"`
8486
Rapl Rapl `yaml:"rapl"`
8587
Exporter Exporter `yaml:"exporter"`
86-
Web Web `yaml:"web"`
87-
Debug Debug `yaml:"debug"`
88-
Dev Dev `yaml:"dev"` // WARN: do not expose dev settings as flags
88+
Web Web
89+
Debug Debug `yaml:"debug"`
90+
Dev Dev `yaml:"dev"` // WARN: do not expose dev settings as flags
8991

9092
Kube Kube `yaml:"kube"`
9193
}
@@ -99,6 +101,7 @@ const (
99101
)
100102

101103
const (
104+
DefaultPort = ":28282"
102105
// Flags
103106
LogLevelFlag = "log.level"
104107
LogFormatFlag = "log.format"
@@ -133,6 +136,7 @@ const (
133136

134137
// DefaultConfig returns a Config with default values
135138
func DefaultConfig() *Config {
139+
TLSconfig := ""
136140
cfg := &Config{
137141
Log: Log{
138142
Level: "info",
@@ -166,6 +170,12 @@ func DefaultConfig() *Config {
166170
Kube: Kube{
167171
Enabled: ptr.To(false),
168172
},
173+
Web: Web{
174+
Config: &web.FlagConfig{
175+
WebListenAddresses: &[]string{DefaultPort},
176+
WebConfigFile: &TLSconfig,
177+
},
178+
},
169179
}
170180

171181
cfg.Dev.FakeCpuMeter.Enabled = ptr.To(false)
@@ -245,7 +255,8 @@ func RegisterFlags(app *kingpin.Application) ConfigUpdaterFn {
245255
"Interval for monitoring resources (processes, container, vm, etc...); 0 to disable").Default("5s").Duration()
246256

247257
enablePprof := app.Flag(pprofEnabledFlag, "Enable pprof debug endpoints").Default("false").Bool()
248-
webConfig := app.Flag(WebConfigFlag, "Web config file path").Default("").String()
258+
//webConfig using github.com/prometheus/exporter-toolkit/web/
259+
webConfig := kingpinflag.AddFlags(app, DefaultPort)
249260

250261
// exporters
251262
stdoutExporterEnabled := app.Flag(ExporterStdoutEnabledFlag, "Enable stdout exporter").Default("false").Bool()
@@ -284,7 +295,7 @@ func RegisterFlags(app *kingpin.Application) ConfigUpdaterFn {
284295
}
285296

286297
if flagsSet[WebConfigFlag] {
287-
cfg.Web.Config = *webConfig
298+
cfg.Web.Config = webConfig
288299
}
289300

290301
if flagsSet[ExporterStdoutEnabledFlag] {
@@ -317,7 +328,6 @@ func (c *Config) sanitize() {
317328
c.Log.Format = strings.TrimSpace(c.Log.Format)
318329
c.Host.SysFS = strings.TrimSpace(c.Host.SysFS)
319330
c.Host.ProcFS = strings.TrimSpace(c.Host.ProcFS)
320-
c.Web.Config = strings.TrimSpace(c.Web.Config)
321331

322332
for i := range c.Rapl.Zones {
323333
c.Rapl.Zones[i] = strings.TrimSpace(c.Rapl.Zones[i])
@@ -359,7 +369,13 @@ func (c *Config) Validate(skips ...SkipValidation) error {
359369
errs = append(errs, fmt.Sprintf("invalid log format: %s", c.Log.Format))
360370
}
361371
}
362-
372+
{ // Web config file
373+
if *c.Web.Config.WebConfigFile != "" {
374+
if err := canReadFile(*c.Web.Config.WebConfigFile); err != nil {
375+
errs = append(errs, fmt.Sprintf("invalid web config file. path: %q: %s", *c.Web.Config.WebConfigFile, err.Error()))
376+
}
377+
}
378+
}
363379
{ // Validate host settings
364380
if _, skip := validationSkipped[SkipHostValidation]; !skip {
365381
if err := canReadDir(c.Host.SysFS); err != nil {
@@ -370,13 +386,6 @@ func (c *Config) Validate(skips ...SkipValidation) error {
370386
}
371387
}
372388
}
373-
{ // Web config file
374-
if c.Web.Config != "" {
375-
if err := canReadFile(c.Web.Config); err != nil {
376-
errs = append(errs, fmt.Sprintf("invalid web config file. path: %q: %s", c.Web.Config, err.Error()))
377-
}
378-
}
379-
}
380389
{ // Monitor
381390
if c.Monitor.Interval < 0 {
382391
errs = append(errs, fmt.Sprintf("invalid monitor interval: %s can't be negative", c.Monitor.Interval))

config/config_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
"github.com/alecthomas/kingpin/v2"
14+
"github.com/prometheus/exporter-toolkit/web"
1415
"github.com/stretchr/testify/assert"
1516
"k8s.io/utils/ptr"
1617
)
@@ -22,7 +23,10 @@ func TestDefaultConfig(t *testing.T) {
2223
// Assert default values are set correctly
2324
assert.Equal(t, "info", cfg.Log.Level)
2425
assert.Equal(t, "text", cfg.Log.Format)
25-
assert.Equal(t, "", cfg.Web.Config)
26+
addrs := *cfg.Web.Config.WebListenAddresses
27+
addr := addrs[0]
28+
assert.Equal(t, DefaultPort, addr)
29+
assert.Equal(t, "", *cfg.Web.Config.WebConfigFile)
2630
}
2731

2832
func TestLoadFromYAML(t *testing.T) {
@@ -216,6 +220,7 @@ func TestReadError(t *testing.T) {
216220
func TestInvalidConfigurationValues(t *testing.T) {
217221
// Test validation of configuration values (command line and YAML)
218222
// Create a kingpin app and register flags
223+
unreadableWebConfig := "/from/unreadable/path/web.yaml"
219224
tt := []struct {
220225
name string
221226
config *Config
@@ -288,7 +293,9 @@ func TestInvalidConfigurationValues(t *testing.T) {
288293
name: "unreadable web config",
289294
config: &Config{
290295
Web: Web{
291-
Config: "/from/unreadable/path/web.yaml",
296+
Config: &web.FlagConfig{
297+
WebConfigFile: &unreadableWebConfig,
298+
},
292299
},
293300
},
294301
error: "invalid web config file",
@@ -367,6 +374,7 @@ func TestConfigValidation(t *testing.T) {
367374
}
368375

369376
func TestConfigString(t *testing.T) {
377+
fackWebConfig := "/fake/web.config.yml"
370378
tt := []struct {
371379
name string
372380
config *Config
@@ -404,7 +412,9 @@ func TestConfigString(t *testing.T) {
404412
name: "custom web.config",
405413
config: &Config{
406414
Web: Web{
407-
Config: "/fake/web.config.yml",
415+
Config: &web.FlagConfig{
416+
WebConfigFile: &fackWebConfig,
417+
},
408418
},
409419
},
410420
}}

internal/server/server.go

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"time"
1212

1313
"github.com/prometheus/exporter-toolkit/web"
14+
"github.com/sustainable-computing-io/kepler/config"
1415
"github.com/sustainable-computing-io/kepler/internal/service"
1516
)
1617

@@ -23,22 +24,19 @@ type APIService interface {
2324
// APIServer implements APIServer
2425
type APIServer struct {
2526
// input
26-
logger *slog.Logger
27-
listenAddrs []string
28-
27+
logger *slog.Logger
2928
// http
3029
server *http.Server
3130
mux *http.ServeMux
3231
endpointDescription string
33-
webCfgPath string
32+
webConfig *web.FlagConfig
3433
}
3534

3635
var _ APIService = (*APIServer)(nil)
3736

3837
type Opts struct {
39-
logger *slog.Logger
40-
listenAddrs []string
41-
webCfgPath string
38+
logger *slog.Logger
39+
webConfig *web.FlagConfig
4240
}
4341

4442
// OptionFn is a function sets one more more options in Opts struct
@@ -51,25 +49,31 @@ func WithLogger(logger *slog.Logger) OptionFn {
5149
}
5250
}
5351

54-
// WithListenAddress sets the listening addresses for the APIServer
55-
func WithListenAddress(addr []string) OptionFn {
52+
// WithListen sets the listening addresses and webconfig path for the APIServer
53+
func WithListen(addr []string, path string) OptionFn {
5654
return func(o *Opts) {
57-
o.listenAddrs = addr
55+
o.webConfig = &web.FlagConfig{
56+
WebListenAddresses: &addr,
57+
WebConfigFile: &path,
58+
}
5859
}
5960
}
6061

61-
func WithWebConfig(path string) OptionFn {
62+
func WithWebConfig(Config *web.FlagConfig) OptionFn {
6263
return func(o *Opts) {
63-
o.webCfgPath = path
64+
o.webConfig = Config
6465
}
6566
}
6667

6768
// DefaultOpts returns the default options
6869
func DefaultOpts() Opts {
70+
TLSconfig := ""
6971
return Opts{
70-
logger: slog.Default(),
71-
listenAddrs: []string{":28282"}, // Default HTTP Port
72-
webCfgPath: "", // Not present by default
72+
logger: slog.Default(),
73+
webConfig: &web.FlagConfig{
74+
WebListenAddresses: &[]string{config.DefaultPort},
75+
WebConfigFile: &TLSconfig,
76+
},
7377
}
7478
}
7579

@@ -85,11 +89,10 @@ func NewAPIServer(applyOpts ...OptionFn) *APIServer {
8589
Handler: mux,
8690
}
8791
apiServer := &APIServer{
88-
logger: opts.logger.With("service", "api-server"),
89-
listenAddrs: opts.listenAddrs,
90-
mux: mux,
91-
server: server,
92-
webCfgPath: opts.webCfgPath,
92+
logger: opts.logger.With("service", "api-server"),
93+
mux: mux,
94+
server: server,
95+
webConfig: opts.webConfig,
9396
}
9497

9598
return apiServer
@@ -100,11 +103,7 @@ func (s *APIServer) Name() string {
100103
}
101104

102105
func (s *APIServer) Init() error {
103-
s.logger.Info("Initializing HTTP server", "listening-on", s.listenAddrs)
104-
if len(s.listenAddrs) == 0 {
105-
return fmt.Errorf("no listening address provided")
106-
}
107-
106+
s.logger.Info("Initializing kepler server")
108107
// create landing page that shows all available endpoints
109108
s.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
110109
// Only respond to the root path
@@ -134,23 +133,19 @@ func (s *APIServer) Init() error {
134133
}
135134

136135
func (s *APIServer) Run(ctx context.Context) error {
137-
s.logger.Info("Running HTTP server", "listening-on", s.listenAddrs)
136+
s.logger.Info("Running kepler server")
138137
errCh := make(chan error)
139138
go func() {
140-
webCfg := &web.FlagConfig{
141-
WebListenAddresses: &s.listenAddrs,
142-
WebConfigFile: &s.webCfgPath,
143-
}
144-
errCh <- web.ListenAndServe(s.server, webCfg, s.logger)
139+
errCh <- web.ListenAndServe(s.server, s.webConfig, s.logger)
145140
}()
146141

147142
select {
148143
case <-ctx.Done():
149-
s.logger.Info("shutting down HTTP server on context done")
144+
s.logger.Info("shutting down kepler server on context done")
150145
return nil
151146

152147
case err := <-errCh:
153-
s.logger.Error("HTTP server returned an error", "error", err)
148+
s.logger.Error("kepler server returned an error", "error", err)
154149
return err
155150
}
156151
}

internal/server/server_test.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ func TestNewAPIServer(t *testing.T) {
6060
}, {
6161
name: "with custom listen address",
6262
opts: []OptionFn{
63-
WithListenAddress([]string{":8080", ":8081"}),
63+
WithListen([]string{":8080", ":8081"}, ""),
6464
},
6565
serviceName: "api-server",
6666
}, {
6767
name: "with multiple options",
6868
opts: []OptionFn{
6969
WithLogger(slog.Default().With("test", "custom")),
70-
WithListenAddress([]string{":9090"}),
70+
WithListen([]string{":9090"}, ""),
7171
},
7272
serviceName: "api-server",
7373
}}
@@ -85,11 +85,10 @@ func TestNewAPIServer(t *testing.T) {
8585
// check listen address
8686
{
8787
server := NewAPIServer(
88-
WithListenAddress([]string{":8080", ":8081"}),
88+
WithListen([]string{":8080", ":8081"}, ""),
8989
)
9090

9191
assert.NotNil(t, server)
92-
assert.Equal(t, []string{":8080", ":8081"}, server.listenAddrs)
9392
}
9493
}
9594

@@ -167,13 +166,6 @@ func TestAPIServer_Register(t *testing.T) {
167166
})
168167
}
169168

170-
func TestAPIServer_InitWithNoListenAddr(t *testing.T) {
171-
server := NewAPIServer(WithListenAddress([]string{}))
172-
err := server.Init()
173-
assert.Error(t, err, "Init should fail with no listen address")
174-
assert.Contains(t, err.Error(), "no listening address provided")
175-
}
176-
177169
func TestAPIServer_InitWithContextCancellation(t *testing.T) {
178170
server := NewAPIServer()
179171

@@ -247,7 +239,7 @@ func TestAPIServer_PortConflict(t *testing.T) {
247239
})
248240

249241
// Create our API server with the same port
250-
apiServer := NewAPIServer(WithListenAddress([]string{addr}))
242+
apiServer := NewAPIServer(WithListen([]string{addr}, ""))
251243

252244
// Initing the API server on the same port should fail due to port conflict
253245
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
@@ -281,7 +273,7 @@ func TestAPIServer_RootEndpoint(t *testing.T) {
281273

282274
addr := fmt.Sprintf("127.0.0.1:%d", port)
283275

284-
server := NewAPIServer(WithListenAddress([]string{addr}))
276+
server := NewAPIServer(WithListen([]string{addr}, ""))
285277
assert.NoError(t, server.Init())
286278

287279
testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)