Skip to content

Commit

Permalink
Metrics configuration
Browse files Browse the repository at this point in the history
Related to #124
I created a MetricsAddress field.  The default port value is “0.0.0.0:8080" and defines where Prometheus metrics endpoint is listening. (see: https://docs.openshift.com/container-platform/4.1/applications/operator_sdk/osdk-monitoring-prometheus.html#osdk-monitoring-prometheus-metrics-helper_osdk-monitoring-prometheus)

I also removed flag.StringVar `"metrics-addr", ":8080”,` from `main.go` as moving inputs into depresolver (following PR will remove flags completely).

Signed-off-by: kuritka <kuritka@gmail.com>
  • Loading branch information
kuritka committed Jun 15, 2021
1 parent 8f06209 commit bf4a0c5
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 5 deletions.
2 changes: 2 additions & 0 deletions controllers/depresolver/depresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ type Config struct {
CoreDNSExposed bool
// Log configuration
Log Log
// MetricsAddress in format address:port where address can be empty, IP address, or hostname, default: 0.0.0.0:8080
MetricsAddress string
// route53Enabled hidden. EdgeDNSType defines all enabled Enabled types
route53Enabled bool
// ns1Enabled flag
Expand Down
27 changes: 27 additions & 0 deletions controllers/depresolver/depresolver_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package depresolver

import (
"fmt"
"strconv"
"strings"

"github.com/AbsaOSS/gopkg/env"
Expand Down Expand Up @@ -51,6 +52,7 @@ const (
LogFormatKey = "LOG_FORMAT"
LogNoColorKey = "NO_COLOR"
SplitBrainCheckKey = "SPLIT_BRAIN_CHECK"
MetricsAddressKey = "METRICS_ADDRESS"
)

// ResolveOperatorConfig executes once. It reads operator's configuration
Expand Down Expand Up @@ -81,6 +83,7 @@ func (dr *DependencyResolver) ResolveOperatorConfig() (*Config, error) {
dr.config.Log.Level, _ = zerolog.ParseLevel(strings.ToLower(env.GetEnvAsStringOrFallback(LogLevelKey, zerolog.InfoLevel.String())))
dr.config.Log.Format = parseLogOutputFormat(strings.ToLower(env.GetEnvAsStringOrFallback(LogFormatKey, SimpleFormat.String())))
dr.config.Log.NoColor = env.GetEnvAsBoolOrFallback(LogNoColorKey, false)
dr.config.MetricsAddress = env.GetEnvAsStringOrFallback(MetricsAddressKey, "0.0.0.0:8080")
dr.config.SplitBrainCheck = env.GetEnvAsBoolOrFallback(SplitBrainCheckKey, false)
dr.config.EdgeDNSType, recognizedDNSTypes = getEdgeDNSType(dr.config)
dr.errorConfig = dr.validateConfig(dr.config, recognizedDNSTypes)
Expand Down Expand Up @@ -193,9 +196,33 @@ func (dr *DependencyResolver) validateConfig(config *Config, recognizedDNSTypes
return fmt.Errorf("error for geo tag: %s. %s in ns name %s", geoTag, err, nsName)
}
}

mHost, mPort, err := parseMetricsAddr(config.MetricsAddress)
if err != nil {
return fmt.Errorf("invalid %s: expecting MetricsAddress in form {host}:port (%s)", MetricsAddressKey, err)
}
err = field(MetricsAddressKey, mHost).matchRegexps(hostNameRegex, ipAddressRegex).err
if err != nil {
return err
}
err = field(MetricsAddressKey, mPort).isLessOrEqualTo(65535).isHigherThan(1024).err
if err != nil {
return err
}
return nil
}

func parseMetricsAddr(metricsAddr string) (host string, port int, err error) {
ma := strings.Split(metricsAddr, ":")
if len(ma) != 2 {
err = fmt.Errorf("invalid format {host}:port (%s)", metricsAddr)
return
}
host = ma[0]
port, err = strconv.Atoi(ma[1])
return
}

// getEdgeDNSType contains logic retrieving EdgeDNSType.
func getEdgeDNSType(config *Config) (EdgeDNSType, []EdgeDNSType) {
recognized := make([]EdgeDNSType, 0)
Expand Down
89 changes: 88 additions & 1 deletion controllers/depresolver/depresolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ var predefinedConfig = Config{
DNSZone: "cloud.example.com",
K8gbNamespace: "k8gb",
SplitBrainCheck: true,
MetricsAddress: "0.0.0.0:8080",
Infoblox: Infoblox{
"Infoblox.host.com",
"0.0.3",
Expand Down Expand Up @@ -176,6 +177,7 @@ func TestResolveConfigWithoutEnvVarsSet(t *testing.T) {
defaultConfig.Log.Level = zerolog.InfoLevel
defaultConfig.Log.Format = SimpleFormat
defaultConfig.Log.NoColor = false
defaultConfig.MetricsAddress = "0.0.0.0:8080"
resolver := NewDependencyResolver()
// act
config, err := resolver.ResolveOperatorConfig()
Expand Down Expand Up @@ -1557,6 +1559,90 @@ func TestNsServerNamesWithExceededDNSNameSize(t *testing.T) {
assert.Len(t, config.GetExternalClusterNSNames()[customConfig.ExtClustersGeoTags[1]], 253)
}

func TestMetricsAddressIsValid(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "0.0.0.0:9091"
arrangeVariablesAndAssert(t, expected, assert.NoError)
}

func TestMetricsAddressPortLimitExceed(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "0.0.0.0:80091"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressPortLimitUnder(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "0.0.0.0:1023"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressInvalidPort(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "0.0.0.0:808x"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressInvalidHost(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "x.y.z??:8080"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressWrongFormatMultipleParts(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "0.0.0.0:8080:9090"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressWrongFormatSinglePart(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "0.0.0.08080"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressInvalidEnvVariable(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "invalid"
arrangeVariablesAndAssert(t, expected, assert.Error)
}

func TestMetricsAddressEmptyHost(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = ":8080"
arrangeVariablesAndAssert(t, expected, assert.NoError)
}

func TestMetricsAddressWithValidHostName(t *testing.T) {
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = "address.com:8080"
arrangeVariablesAndAssert(t, expected, assert.NoError)
}

func TestMetricsAddressEmptyEnvVariable(t *testing.T) {
// arrange
defer cleanup()
expected := predefinedConfig
expected.MetricsAddress = ""
configureEnvVar(expected)
resolver := NewDependencyResolver()
// act
config, err := resolver.ResolveOperatorConfig()
// assert
assert.NoError(t, err)
assert.Equal(t, "0.0.0.0:8080", config.MetricsAddress)
}

// arrangeVariablesAndAssert sets string environment variables and asserts `expected` argument with
// ResolveOperatorConfig() output. The last parameter unsets the values
func arrangeVariablesAndAssert(t *testing.T, expected Config,
Expand All @@ -1580,7 +1666,7 @@ func cleanup() {
for _, s := range []string{ReconcileRequeueSecondsKey, ClusterGeoTagKey, ExtClustersGeoTagsKey, EdgeDNSZoneKey, DNSZoneKey, EdgeDNSServerKey,
EdgeDNSServerPortKey, Route53EnabledKey, NS1EnabledKey, InfobloxGridHostKey, InfobloxVersionKey, InfobloxPortKey, InfobloxUsernameKey,
InfobloxPasswordKey, OverrideFakeInfobloxKey, K8gbNamespaceKey, CoreDNSExposedKey, InfobloxHTTPRequestTimeoutKey,
InfobloxHTTPPoolConnectionsKey, LogLevelKey, LogFormatKey, LogNoColorKey, SplitBrainCheckKey} {
InfobloxHTTPPoolConnectionsKey, LogLevelKey, LogFormatKey, LogNoColorKey, MetricsAddressKey, SplitBrainCheckKey} {
if os.Unsetenv(s) != nil {
panic(fmt.Errorf("cleanup %s", s))
}
Expand Down Expand Up @@ -1610,6 +1696,7 @@ func configureEnvVar(config Config) {
_ = os.Setenv(LogLevelKey, config.Log.Level.String())
_ = os.Setenv(LogFormatKey, config.Log.Format.String())
_ = os.Setenv(LogNoColorKey, strconv.FormatBool(config.Log.NoColor))
_ = os.Setenv(MetricsAddressKey, config.MetricsAddress)
_ = os.Setenv(SplitBrainCheckKey, strconv.FormatBool(config.SplitBrainCheck))
}

Expand Down
20 changes: 20 additions & 0 deletions controllers/depresolver/depresolver_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ func (v *validator) isNotEmpty() *validator {
return v
}

func (v *validator) startsWith(prefix string) *validator {
if v.err != nil {
return v
}
if strings.HasPrefix(v.strValue, prefix) {
v.err = fmt.Errorf("'%s' must start with '%s'", v.name, prefix)
}
return v
}

func (v *validator) matchRegexp(regex string) *validator {
if v.err != nil {
return v
Expand Down Expand Up @@ -139,6 +149,16 @@ func (v *validator) isLessOrEqualTo(num int) *validator {
return v
}

func (v *validator) isHigherThan(num int) *validator {
if v.err != nil {
return v
}
if v.intValue <= num {
v.err = fmt.Errorf(`'%s' is higher than '%v'`, v.name, num)
}
return v
}

func (v *validator) isNotEqualTo(value string) *validator {
if v.err != nil {
return v
Expand Down
2 changes: 1 addition & 1 deletion controllers/gslb_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func (r *GslbReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.

// SetupWithManager configures controller manager
func (r *GslbReconciler) SetupWithManager(mgr ctrl.Manager) error {
// Figure out Gslb resource name to Reconcile when non controlled Endpoint is updated
// Figure out Gslb resource name to Reconcile when non controlled Name is updated

endpointMapHandler := handler.EnqueueRequestsFromMapFunc(
func(a client.Object) []reconcile.Request {
Expand Down
4 changes: 1 addition & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ func init() {
}

func main() {
var metricsAddr string
var enableLeaderElection bool
var f *dns.ProviderFactory
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
Expand All @@ -75,7 +73,7 @@ func main() {

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: runtimescheme,
MetricsBindAddress: metricsAddr,
MetricsBindAddress: config.MetricsAddress,
Port: 9443,
LeaderElection: enableLeaderElection,
LeaderElectionID: "8020e9ff.absa.oss",
Expand Down

0 comments on commit bf4a0c5

Please sign in to comment.