Skip to content

Commit d804edb

Browse files
authored
Prior config refactoring before adding prometheus config (#511)
- Merged the different Config structs (from handler.Config, server.Config and loki.Config) in a dedicated config package - Add names to table-based tests - A few linter fixes (e.g. space after comments)
1 parent 9cc4ec8 commit d804edb

22 files changed

+384
-421
lines changed

cmd/plugin-backend.go

Lines changed: 8 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,11 @@ package main
33
import (
44
"flag"
55
"fmt"
6-
"net/url"
76
"os"
8-
"strings"
9-
"time"
107

118
"github.com/sirupsen/logrus"
129

13-
"github.com/netobserv/network-observability-console-plugin/pkg/handler"
14-
"github.com/netobserv/network-observability-console-plugin/pkg/kubernetes/auth"
15-
"github.com/netobserv/network-observability-console-plugin/pkg/kubernetes/client"
16-
"github.com/netobserv/network-observability-console-plugin/pkg/loki"
10+
"github.com/netobserv/network-observability-console-plugin/pkg/config"
1711
"github.com/netobserv/network-observability-console-plugin/pkg/server"
1812
)
1913

@@ -45,104 +39,21 @@ func main() {
4539
logrus.SetLevel(lvl)
4640
log.Infof("Starting %s at log level %s", appVersion, *logLevel)
4741

48-
config, err := handler.ReadConfigFile(buildVersion, buildDate, *configPath)
42+
cfg, err := config.ReadFile(buildVersion, buildDate, *configPath)
4943
if err != nil {
5044
log.WithError(err).Fatal("error reading config file")
5145
}
5246

53-
// check config required fields
54-
var configErrors []string
55-
if len(config.Loki.Labels) == 0 {
56-
configErrors = append(configErrors, "labels cannot be empty")
57-
}
58-
59-
// parse config urls
60-
var lURL, lStatusURL *url.URL
61-
if len(config.Loki.URL) == 0 {
62-
configErrors = append(configErrors, "url cannot be empty")
63-
} else {
64-
lURL, err = url.Parse(config.Loki.URL)
65-
if err != nil {
66-
configErrors = append(configErrors, "wrong Loki URL")
67-
}
68-
}
69-
if len(config.Loki.StatusURL) > 0 {
70-
lStatusURL, err = url.Parse(config.Loki.StatusURL)
71-
if err != nil {
72-
configErrors = append(configErrors, "wrong Loki status URL")
73-
}
74-
} else {
75-
lStatusURL = lURL
76-
}
77-
78-
// parse config timeout
79-
ltimeout, err := time.ParseDuration(config.Loki.Timeout)
80-
if err != nil {
81-
configErrors = append(configErrors, "wrong Loki timeout")
82-
}
83-
84-
// parse config auth
85-
var checkType auth.CheckType
86-
if config.Loki.AuthCheck == "auto" {
87-
if config.Loki.ForwardUserToken {
88-
// FORWARD lokiAuth mode
89-
checkType = auth.CheckAuthenticated
90-
} else {
91-
// HOST or DISABLED lokiAuth mode
92-
checkType = auth.CheckAdmin
93-
}
94-
log.Info(fmt.Sprintf("auth-check 'auto' resolved to '%s'", checkType))
95-
} else {
96-
checkType = auth.CheckType(config.Loki.AuthCheck)
97-
}
98-
if checkType == auth.CheckNone {
99-
log.Warn("INSECURE: auth checker is disabled")
100-
}
101-
checker, err := auth.NewChecker(checkType, client.NewInCluster)
47+
checker, err := cfg.GetAuthChecker()
10248
if err != nil {
103-
configErrors = append(configErrors, "auth checker error")
104-
}
105-
106-
// crash on config errors
107-
if len(configErrors) > 0 {
108-
configErrors = append([]string{fmt.Sprintf("Config file has %d errors:\n", len(configErrors))}, configErrors...)
109-
log.Fatal(strings.Join(configErrors, "\n - "))
49+
log.WithError(err).Fatal("auth checker error")
11050
}
11151

11252
go server.StartMetrics(&server.MetricsConfig{
113-
Port: config.Server.MetricsPort,
114-
CertPath: config.Server.CertPath,
115-
KeyPath: config.Server.KeyPath,
53+
Port: cfg.Server.MetricsPort,
54+
CertPath: cfg.Server.CertPath,
55+
KeyPath: cfg.Server.KeyPath,
11656
})
11757

118-
server.Start(&server.Config{
119-
BuildVersion: buildVersion,
120-
BuildDate: buildDate,
121-
Port: config.Server.Port,
122-
CertPath: config.Server.CertPath,
123-
KeyPath: config.Server.KeyPath,
124-
CORSAllowOrigin: config.Server.CORSOrigin,
125-
CORSAllowMethods: config.Server.CORSMethods,
126-
CORSAllowHeaders: config.Server.CORSHeaders,
127-
CORSMaxAge: config.Server.CORSMaxAge,
128-
ConfigPath: *configPath,
129-
Loki: loki.NewConfig(
130-
lURL,
131-
lStatusURL,
132-
ltimeout,
133-
config.Loki.TenantID,
134-
config.Loki.TokenPath,
135-
config.Loki.ForwardUserToken,
136-
config.Loki.SkipTLS,
137-
config.Loki.CAPath,
138-
config.Loki.StatusSkipTLS,
139-
config.Loki.CAPath,
140-
config.Loki.StatusUserCertPath,
141-
config.Loki.StatusUserKeyPath,
142-
config.Loki.UseMocks,
143-
config.Loki.Labels,
144-
config.Frontend.Deduper.Mark,
145-
config.Frontend.Deduper.Merge,
146-
),
147-
}, checker)
58+
server.Start(cfg, checker)
14859
}

pkg/handler/config.go renamed to pkg/config/config.go

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
package handler
1+
package config
22

33
import (
4-
"net/http"
4+
"fmt"
5+
"net/url"
56
"os"
7+
"strings"
8+
"time"
69

10+
"github.com/netobserv/network-observability-console-plugin/pkg/kubernetes/auth"
11+
"github.com/netobserv/network-observability-console-plugin/pkg/kubernetes/client"
12+
"github.com/sirupsen/logrus"
713
"gopkg.in/yaml.v3"
814
)
915

16+
var (
17+
log = logrus.WithField("module", "config")
18+
)
19+
1020
type Server struct {
1121
Port int `yaml:"port,omitempty" json:"port,omitempty"`
1222
MetricsPort int `yaml:"metricsPort,omitempty" json:"metricsPort,omitempty"`
@@ -18,25 +28,6 @@ type Server struct {
1828
CORSMaxAge string `yaml:"corsMaxAge,omitempty" json:"corsMaxAge,omitempty"`
1929
}
2030

21-
type Loki struct {
22-
URL string `yaml:"url" json:"url"`
23-
Labels []string `yaml:"labels" json:"labels"`
24-
25-
StatusURL string `yaml:"statusUrl,omitempty" json:"statusUrl,omitempty"`
26-
Timeout string `yaml:"timeout,omitempty" json:"timeout,omitempty"`
27-
TenantID string `yaml:"tenantID,omitempty" json:"tenantID,omitempty"`
28-
TokenPath string `yaml:"tokenPath,omitempty" json:"tokenPath,omitempty"`
29-
SkipTLS bool `yaml:"skipTls,omitempty" json:"skipTls,omitempty"`
30-
CAPath string `yaml:"caPath,omitempty" json:"caPath,omitempty"`
31-
StatusSkipTLS bool `yaml:"statusSkipTls,omitempty" json:"statusSkipTls,omitempty"`
32-
StatusCAPath string `yaml:"statusCaPath,omitempty" json:"statusCaPath,omitempty"`
33-
StatusUserCertPath string `yaml:"statusUserCertPath,omitempty" json:"statusUserCertPath,omitempty"`
34-
StatusUserKeyPath string `yaml:"statusUserKeyPath,omitempty" json:"statusUserKeyPath,omitempty"`
35-
UseMocks bool `yaml:"useMocks,omitempty" json:"useMocks,omitempty"`
36-
ForwardUserToken bool `yaml:"forwardUserToken,omitempty" json:"forwardUserToken,omitempty"`
37-
AuthCheck string `yaml:"authCheck,omitempty" json:"authCheck,omitempty"`
38-
}
39-
4031
type PortNaming struct {
4132
Enable bool `yaml:"enable" json:"enable"`
4233
PortNames map[string]string `yaml:"portNames" json:"portNames"`
@@ -110,21 +101,22 @@ type Frontend struct {
110101
type Config struct {
111102
Loki Loki `yaml:"loki" json:"loki"`
112103
Frontend Frontend `yaml:"frontend" json:"frontend"`
113-
114-
Server Server `yaml:"server,omitempty" json:"server,omitempty"`
104+
Server Server `yaml:"server,omitempty" json:"server,omitempty"`
105+
Path string `yaml:"-" json:"-"`
115106
}
116107

117-
func ReadConfigFile(version, date, filename string) (*Config, error) {
118-
//set default vales
108+
func ReadFile(version, date, filename string) (*Config, error) {
109+
// set default values
119110
cfg := Config{
111+
Path: filename,
120112
Server: Server{
121113
Port: 9001,
122114
MetricsPort: 9002,
123115
CORSOrigin: "*",
124116
CORSHeaders: "Origin, X-Requested-With, Content-Type, Accept",
125117
},
126118
Loki: Loki{
127-
Timeout: "30s",
119+
Timeout: Duration{Duration: 30 * time.Second},
128120
AuthCheck: "auto",
129121
},
130122
Frontend: Frontend{
@@ -140,10 +132,9 @@ func ReadConfigFile(version, date, filename string) (*Config, error) {
140132
Filters: []Filter{},
141133
QuickFilters: []QuickFilter{},
142134
Features: []string{},
143-
// TODO: update these defaults when operator will move to merge mode
144135
Deduper: Deduper{
145-
Mark: true,
146-
Merge: false,
136+
Mark: false,
137+
Merge: true,
147138
},
148139
Fields: []FieldConfig{
149140
{Name: "TimeFlowEndMs", Type: "number"},
@@ -160,24 +151,63 @@ func ReadConfigFile(version, date, filename string) (*Config, error) {
160151
return nil, err
161152
}
162153
err = yaml.Unmarshal(yamlFile, &cfg)
163-
return &cfg, err
154+
if err != nil {
155+
return nil, err
156+
}
157+
158+
cfg.Validate()
159+
160+
return &cfg, nil
164161
}
165162

166-
func GetFrontendConfig(version, date, filename string) func(w http.ResponseWriter, r *http.Request) {
167-
config, err := ReadConfigFile(version, date, filename)
168-
if err != nil {
169-
hlog.Errorf("Could not read config file: %v", err)
163+
func (c *Config) Validate() {
164+
var configErrors []string
165+
166+
// check config required fields
167+
if len(c.Loki.Labels) == 0 {
168+
configErrors = append(configErrors, "labels cannot be empty")
170169
}
171-
return func(w http.ResponseWriter, r *http.Request) {
170+
171+
// parse config urls
172+
if len(c.Loki.URL) == 0 {
173+
configErrors = append(configErrors, "url cannot be empty")
174+
} else {
175+
_, err := url.Parse(c.Loki.URL)
176+
if err != nil {
177+
configErrors = append(configErrors, "wrong Loki URL")
178+
}
179+
}
180+
if len(c.Loki.StatusURL) > 0 {
181+
_, err := url.Parse(c.Loki.StatusURL)
172182
if err != nil {
173-
config, err = ReadConfigFile(version, date, filename)
174-
if err != nil {
175-
writeError(w, http.StatusInternalServerError, err.Error())
176-
} else {
177-
writeJSON(w, http.StatusOK, config.Frontend)
178-
}
183+
configErrors = append(configErrors, "wrong Loki status URL")
184+
}
185+
}
186+
187+
// crash on config errors
188+
if len(configErrors) > 0 {
189+
configErrors = append([]string{fmt.Sprintf("Config file has %d errors:\n", len(configErrors))}, configErrors...)
190+
log.Fatal(strings.Join(configErrors, "\n - "))
191+
}
192+
}
193+
194+
func (c *Config) GetAuthChecker() (auth.Checker, error) {
195+
// parse config auth
196+
var checkType auth.CheckType
197+
if c.Loki.AuthCheck == "auto" {
198+
if c.Loki.ForwardUserToken {
199+
// FORWARD lokiAuth mode
200+
checkType = auth.CheckAuthenticated
179201
} else {
180-
writeJSON(w, http.StatusOK, config.Frontend)
202+
// HOST or DISABLED lokiAuth mode
203+
checkType = auth.CheckAdmin
181204
}
205+
log.Info(fmt.Sprintf("auth-check 'auto' resolved to '%s'", checkType))
206+
} else {
207+
checkType = auth.CheckType(c.Loki.AuthCheck)
208+
}
209+
if checkType == auth.CheckNone {
210+
log.Warn("INSECURE: auth checker is disabled")
182211
}
212+
return auth.NewChecker(checkType, client.NewInCluster)
183213
}

pkg/config/duration.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package config
2+
3+
// TODO: move this file in a new netobserv-libs repo ? (Same in FLP)
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
"time"
9+
)
10+
11+
// Duration is a wrapper of time.Duration that allows json marshaling.
12+
type Duration struct {
13+
time.Duration
14+
}
15+
16+
func (d Duration) MarshalJSON() ([]byte, error) {
17+
return json.Marshal(d.String())
18+
}
19+
20+
func (d *Duration) UnmarshalJSON(b []byte) error {
21+
var v interface{}
22+
if err := json.Unmarshal(b, &v); err != nil {
23+
return err
24+
}
25+
switch value := v.(type) {
26+
case float64:
27+
d.Duration = time.Duration(value)
28+
return nil
29+
case string:
30+
var err error
31+
d.Duration, err = time.ParseDuration(value)
32+
if err != nil {
33+
return err
34+
}
35+
return nil
36+
default:
37+
return fmt.Errorf("invalid duration %v", value)
38+
}
39+
}
40+
41+
func (d Duration) MarshalYAML() (interface{}, error) {
42+
return d.String(), nil
43+
}
44+
45+
func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
46+
var durationStr string
47+
err := unmarshal(&durationStr)
48+
if err != nil {
49+
return err
50+
}
51+
d.Duration, err = time.ParseDuration(durationStr)
52+
if err != nil {
53+
return err
54+
}
55+
return nil
56+
}

pkg/config/loki.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package config
2+
3+
import "github.com/netobserv/network-observability-console-plugin/pkg/utils"
4+
5+
type Loki struct {
6+
URL string `yaml:"url" json:"url"`
7+
Labels []string `yaml:"labels" json:"labels"`
8+
StatusURL string `yaml:"statusUrl,omitempty" json:"statusUrl,omitempty"`
9+
Timeout Duration `yaml:"timeout,omitempty" json:"timeout,omitempty"`
10+
TenantID string `yaml:"tenantID,omitempty" json:"tenantID,omitempty"`
11+
TokenPath string `yaml:"tokenPath,omitempty" json:"tokenPath,omitempty"`
12+
SkipTLS bool `yaml:"skipTls,omitempty" json:"skipTls,omitempty"`
13+
CAPath string `yaml:"caPath,omitempty" json:"caPath,omitempty"`
14+
StatusSkipTLS bool `yaml:"statusSkipTls,omitempty" json:"statusSkipTls,omitempty"`
15+
StatusCAPath string `yaml:"statusCaPath,omitempty" json:"statusCaPath,omitempty"`
16+
StatusUserCertPath string `yaml:"statusUserCertPath,omitempty" json:"statusUserCertPath,omitempty"`
17+
StatusUserKeyPath string `yaml:"statusUserKeyPath,omitempty" json:"statusUserKeyPath,omitempty"`
18+
UseMocks bool `yaml:"useMocks,omitempty" json:"useMocks,omitempty"`
19+
ForwardUserToken bool `yaml:"forwardUserToken,omitempty" json:"forwardUserToken,omitempty"`
20+
AuthCheck string `yaml:"authCheck,omitempty" json:"authCheck,omitempty"`
21+
labelsMap map[string]struct{}
22+
}
23+
24+
func (l *Loki) GetStatusURL() string {
25+
if l.StatusURL != "" {
26+
return l.StatusURL
27+
}
28+
return l.URL
29+
}
30+
31+
func (l *Loki) IsLabel(key string) bool {
32+
if l.labelsMap == nil {
33+
l.labelsMap = utils.GetMapInterface(l.Labels)
34+
}
35+
_, isLabel := l.labelsMap[key]
36+
return isLabel
37+
}

0 commit comments

Comments
 (0)