Skip to content

Commit

Permalink
Merge pull request #19 from configcat/private-status
Browse files Browse the repository at this point in the history
Status endpoint port configuration / Fix wrong response bug
  • Loading branch information
z4kn4fein authored Mar 7, 2024
2 parents 5cc778c + 503a402 commit a6eed5a
Show file tree
Hide file tree
Showing 43 changed files with 305 additions and 209 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ There are three ways how the Proxy is informed about the availability of new fea
- **Cache polling / file watching**: In [offline mode](https://configcat.com/docs/advanced/proxy/proxy-overview#offline-mode), the Proxy can regularly poll a cache or watch a file for new *config JSON* versions.

These are the ports used by the Proxy by default:
- **8050**: for standard HTTP communication. ([API](https://configcat.com/docs/advanced/proxy/endpoints#api), [CDN proxy](https://configcat.com/docs/advanced/proxy/endpoints#cdn-proxy), [Webhook](https://configcat.com/docs/advanced/proxy/endpoints#webhook), [SSE](https://configcat.com/docs/advanced/proxy/endpoints#sse), [Status](https://configcat.com/docs/advanced/proxy/monitoring#status))
- **8051**: for providing [prometheus metrics](https://configcat.com/docs/advanced/proxy/monitoring#prometheus-metrics).
- **8050**: for standard HTTP communication. ([API](https://configcat.com/docs/advanced/proxy/endpoints#api), [CDN proxy](https://configcat.com/docs/advanced/proxy/endpoints#cdn-proxy), [Webhook](https://configcat.com/docs/advanced/proxy/endpoints#webhook), [SSE](https://configcat.com/docs/advanced/proxy/endpoints#sse))
- **8051**: for providing diagnostic data ([status](https://configcat.com/docs/advanced/proxy/monitoring#status), [prometheus metrics](https://configcat.com/docs/advanced/proxy/monitoring#prometheus-metrics)).
- **50051**: for [gRPC](https://configcat.com/docs/advanced/proxy/grpc) communication.

## Installation
Expand Down Expand Up @@ -83,7 +83,7 @@ Using with `docker-compose`:
You can download the executables directly from <a target="_blank" href="https://github.com/configcat/configcat-proxy/releases">GitHub Releases</a> for your desired platform.

## Health Check
After installation, you can check the [status endpoint](https://configcat.com/docs/advanced/proxy/monitoring#status) of the Proxy to ensure it's working correctly: `http(s)://localhost:8050/status`
After installation, you can check the [status endpoint](https://configcat.com/docs/advanced/proxy/monitoring#status) of the Proxy to ensure it's working correctly: `http://localhost:8051/status`
## Need help?
https://configcat.com/support
Expand Down
23 changes: 19 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Config struct {
SDKs map[string]*SDKConfig
Grpc GrpcConfig
Tls TlsConfig
Metrics MetricsConfig
Diag DiagConfig
Http HttpConfig
Cache CacheConfig
HttpProxy HttpProxyConfig `yaml:"http_proxy"`
Expand Down Expand Up @@ -83,6 +83,7 @@ type HttpConfig struct {
Webhook WebhookConfig
Sse SseConfig
Api ApiConfig
Status StatusConfig
}

type WebhookConfig struct {
Expand Down Expand Up @@ -170,9 +171,19 @@ type TlsConfig struct {
Certificates []CertConfig
}

type DiagConfig struct {
Port int `yaml:"port"`
Enabled bool `yaml:"enabled"`
Metrics MetricsConfig `yaml:"metrics"`
Status StatusConfig `yaml:"status"`
}

type MetricsConfig struct {
Enabled bool `yaml:"enabled"`
Port int `yaml:"port"`
}

type StatusConfig struct {
Enabled bool `yaml:"enabled"`
}

func LoadConfigFromFileAndEnvironment(filePath string) (Config, error) {
Expand Down Expand Up @@ -243,8 +254,10 @@ func (c *Config) setDefaults() {
c.Grpc.Enabled = true
c.Grpc.Port = 50051

c.Metrics.Enabled = true
c.Metrics.Port = 8051
c.Diag.Enabled = true
c.Diag.Status.Enabled = true
c.Diag.Metrics.Enabled = true
c.Diag.Port = 8051

c.Http.Sse.Enabled = true
c.Http.Sse.CORS.Enabled = true
Expand All @@ -257,6 +270,8 @@ func (c *Config) setDefaults() {

c.Http.Webhook.Enabled = true

c.Http.Status.Enabled = false

c.Cache.Redis.DB = 0
c.Cache.Redis.Addresses = []string{"localhost:6379"}
}
Expand Down
26 changes: 20 additions & 6 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ func TestConfig_Defaults(t *testing.T) {
assert.Equal(t, 50051, conf.Grpc.Port)
assert.True(t, conf.Grpc.Enabled)

assert.Equal(t, 8051, conf.Metrics.Port)
assert.True(t, conf.Metrics.Enabled)
assert.Equal(t, 8051, conf.Diag.Port)
assert.True(t, conf.Diag.Enabled)
assert.True(t, conf.Diag.Status.Enabled)
assert.True(t, conf.Diag.Metrics.Enabled)

assert.True(t, conf.Http.Sse.Enabled)
assert.True(t, conf.Http.Sse.CORS.Enabled)
Expand All @@ -32,6 +34,8 @@ func TestConfig_Defaults(t *testing.T) {

assert.True(t, conf.Http.Webhook.Enabled)

assert.False(t, conf.Http.Status.Enabled)

assert.False(t, conf.GlobalOfflineConfig.Enabled)
assert.Equal(t, 5, conf.GlobalOfflineConfig.CachePollInterval)

Expand Down Expand Up @@ -373,17 +377,23 @@ log:
})
}

func TestMetricsConfig_YAML(t *testing.T) {
func TestDiagConfig_YAML(t *testing.T) {
utils.UseTempFile(`
metrics:
diag:
enabled: false
port: 8091
status:
enabled: false
metrics:
enabled: false
`, func(file string) {
conf, err := LoadConfigFromFileAndEnvironment(file)
require.NoError(t, err)

assert.False(t, conf.Metrics.Enabled)
assert.Equal(t, 8091, conf.Metrics.Port)
assert.False(t, conf.Diag.Enabled)
assert.Equal(t, 8091, conf.Diag.Port)
assert.False(t, conf.Diag.Status.Enabled)
assert.False(t, conf.Diag.Metrics.Enabled)
})
}

Expand Down Expand Up @@ -429,6 +439,8 @@ http:
headers:
CUSTOM-HEADER1: "sse-val1"
CUSTOM-HEADER2: "sse-val2"
status:
enabled: true
`, func(file string) {
conf, err := LoadConfigFromFileAndEnvironment(file)
require.NoError(t, err)
Expand Down Expand Up @@ -463,6 +475,8 @@ http:
assert.Equal(t, "api-val2", conf.Http.Api.Headers["CUSTOM-HEADER2"])
assert.Equal(t, "api-auth1", conf.Http.Api.AuthHeaders["X-API-KEY1"])
assert.Equal(t, "api-auth2", conf.Http.Api.AuthHeaders["X-API-KEY2"])

assert.True(t, conf.Http.Status.Enabled)
})
}

Expand Down
29 changes: 27 additions & 2 deletions config/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (c *Config) loadEnv() error {
if err := c.Tls.loadEnv(envPrefix); err != nil {
return err
}
if err := c.Metrics.loadEnv(envPrefix); err != nil {
if err := c.Diag.loadEnv(envPrefix); err != nil {
return err
}
if err := c.Cache.loadEnv(envPrefix); err != nil {
Expand Down Expand Up @@ -133,6 +133,9 @@ func (h *HttpConfig) loadEnv(prefix string) error {
if err := h.Webhook.loadEnv(prefix); err != nil {
return err
}
if err := h.Status.loadEnv(prefix); err != nil {
return err
}
return h.Api.loadEnv(prefix)
}

Expand Down Expand Up @@ -309,12 +312,34 @@ func (l *LogConfig) loadEnv(prefix string) error {
return nil
}

func (d *DiagConfig) loadEnv(prefix string) error {
prefix = concatPrefix(prefix, "DIAG")
if err := readEnv(prefix, "ENABLED", &d.Enabled, toBool); err != nil {
return err
}
if err := readEnv(prefix, "PORT", &d.Port, toInt); err != nil {
return err
}
if err := d.Status.loadEnv(prefix); err != nil {
return err
}
if err := d.Metrics.loadEnv(prefix); err != nil {
return err
}
return nil
}

func (m *MetricsConfig) loadEnv(prefix string) error {
prefix = concatPrefix(prefix, "METRICS")
if err := readEnv(prefix, "ENABLED", &m.Enabled, toBool); err != nil {
return err
}
if err := readEnv(prefix, "PORT", &m.Port, toInt); err != nil {
return nil
}

func (s *StatusConfig) loadEnv(prefix string) error {
prefix = concatPrefix(prefix, "STATUS")
if err := readEnv(prefix, "ENABLED", &s.Enabled, toBool); err != nil {
return err
}
return nil
Expand Down
17 changes: 12 additions & 5 deletions config/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,19 @@ func TestLogConfig_ENV(t *testing.T) {
assert.Equal(t, log.Error, conf.Log.GetLevel())
}

func TestMetricsConfig_ENV(t *testing.T) {
t.Setenv("CONFIGCAT_METRICS_ENABLED", "false")
t.Setenv("CONFIGCAT_METRICS_PORT", "8091")
func TestDiagConfig_ENV(t *testing.T) {
t.Setenv("CONFIGCAT_DIAG_ENABLED", "false")
t.Setenv("CONFIGCAT_DIAG_PORT", "8091")
t.Setenv("CONFIGCAT_DIAG_METRICS_ENABLED", "false")
t.Setenv("CONFIGCAT_DIAG_STATUS_ENABLED", "false")

conf, err := LoadConfigFromFileAndEnvironment("")
require.NoError(t, err)

assert.False(t, conf.Metrics.Enabled)
assert.Equal(t, 8091, conf.Metrics.Port)
assert.False(t, conf.Diag.Enabled)
assert.Equal(t, 8091, conf.Diag.Port)
assert.False(t, conf.Diag.Status.Enabled)
assert.False(t, conf.Diag.Metrics.Enabled)
}

func TestGlobalOfflineConfig_ENV(t *testing.T) {
Expand Down Expand Up @@ -178,6 +182,7 @@ func TestHttpConfig_ENV(t *testing.T) {
t.Setenv("CONFIGCAT_HTTP_API_CORS_ALLOWED_ORIGINS", `["https://example1.com","https://example2.com"]`)
t.Setenv("CONFIGCAT_HTTP_API_HEADERS", `{"CUSTOM-HEADER1": "api-val1", "CUSTOM-HEADER2": "api-val2"}`)
t.Setenv("CONFIGCAT_HTTP_API_AUTH_HEADERS", `{"X-API-KEY1": "api-auth1", "X-API-KEY2": "api-auth2"}`)
t.Setenv("CONFIGCAT_HTTP_STATUS_ENABLED", "true")

conf, err := LoadConfigFromFileAndEnvironment("")
require.NoError(t, err)
Expand Down Expand Up @@ -212,6 +217,8 @@ func TestHttpConfig_ENV(t *testing.T) {
assert.Equal(t, "api-val2", conf.Http.Api.Headers["CUSTOM-HEADER2"])
assert.Equal(t, "api-auth1", conf.Http.Api.AuthHeaders["X-API-KEY1"])
assert.Equal(t, "api-auth2", conf.Http.Api.AuthHeaders["X-API-KEY2"])

assert.True(t, conf.Http.Status.Enabled)
}

func TestCORSConfig_ENV(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions config/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (c *Config) Validate() error {
if err := c.Http.validate(); err != nil {
return err
}
if err := c.Metrics.validate(); err != nil {
if err := c.Diag.validate(); err != nil {
return err
}
if err := c.Grpc.validate(); err != nil {
Expand Down Expand Up @@ -170,9 +170,9 @@ func (l *LocalConfig) validate(sdkId string) error {
return nil
}

func (m *MetricsConfig) validate() error {
if m.Port < 1 || m.Port > 65535 {
return fmt.Errorf("metrics: invalid port %d", m.Port)
func (d *DiagConfig) validate() error {
if d.Port < 1 || d.Port > 65535 {
return fmt.Errorf("diag: invalid port %d", d.Port)
}
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions config/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func TestConfig_Validate(t *testing.T) {
require.ErrorContains(t, conf.Validate(), "offline: global offline mode enabled, but no cache is configured")
})
t.Run("redis enabled without addresses", func(t *testing.T) {
conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true}}, Grpc: GrpcConfig{Port: 100}, Metrics: MetricsConfig{Port: 90}, Http: HttpConfig{Port: 80}}
conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true}}, Grpc: GrpcConfig{Port: 100}, Diag: DiagConfig{Port: 90}, Http: HttpConfig{Port: 80}}
require.ErrorContains(t, conf.Validate(), "redis: at least 1 server address required")
})
t.Run("redis invalid tls config", func(t *testing.T) {
Expand Down Expand Up @@ -106,11 +106,11 @@ func TestConfig_Validate(t *testing.T) {
require.ErrorContains(t, conf.Validate(), "http: invalid port -1")
})
t.Run("metrics", func(t *testing.T) {
conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Metrics: MetricsConfig{Port: -1}, Http: HttpConfig{Port: 80}}
require.ErrorContains(t, conf.Validate(), "metrics: invalid port -1")
conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Diag: DiagConfig{Port: -1}, Http: HttpConfig{Port: 80}}
require.ErrorContains(t, conf.Validate(), "diag: invalid port -1")
})
t.Run("grpc", func(t *testing.T) {
conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Grpc: GrpcConfig{Port: -1}, Metrics: MetricsConfig{Port: 90}, Http: HttpConfig{Port: 80}}
conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Grpc: GrpcConfig{Port: -1}, Diag: DiagConfig{Port: 90}, Http: HttpConfig{Port: 80}}
require.ErrorContains(t, conf.Validate(), "grpc: invalid port -1")
})
})
Expand Down
Loading

0 comments on commit a6eed5a

Please sign in to comment.