Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/viper config #7

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ golerta

# Ignore vim temporary files
.*.sw*

#Ignore local vscode configs
.vscode
81 changes: 14 additions & 67 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,69 +1,16 @@
FROM alpine:edge

ENV DOCKERIZE_VERSION 0.2.0
RUN apk add --no-cache ca-certificates curl && \
mkdir -p /usr/local/bin/ && \
curl -SL https://github.com/jwilder/dockerize/releases/download/v${DOCKERIZE_VERSION}/dockerize-linux-amd64-v${DOCKERIZE_VERSION}.tar.gz \
| tar xzC /usr/local/bin

ENV GOPATH /go
ENV GOREPO github.com/allen13/golerta
RUN mkdir -p $GOPATH/src/$GOREPO
COPY . $GOPATH/src/$GOREPO
WORKDIR $GOPATH/src/$GOREPO

RUN set -ex \
&& apk add --no-cache --virtual .build-deps \
git \
go \
build-base \
&& go build golerta.go \
&& apk del .build-deps \
&& rm -rf $GOPATH/pkg
FROM golang:1.10 as build
COPY . /go/src/github.com/allen13/golerta/
WORKDIR /go/src/github.com/allen13/golerta/
ENV GOOS=linux
ENV GOARCH=amd64
ENV CGO_ENABLED=0
RUN SKIP_RETHINKDB=true go test ./app/...
RUN go build -ldflags "-s -w" golerta.go

FROM scratch
EXPOSE 5608

ENV BIND_ADDR :5608
ENV SIGNING_KEY CHANGEME
ENV AUTH_PROVIDER ldap
ENV CONTINUOUS_QUERY_INTERVAL 5s
ENV LOG_ALERT_REQUESTS false
ENV TLS_ENABLED false
ENV TLS_CERT ""
ENV TLS_KEY ""
ENV TLS_AUTO_ENABLED false
ENV TLS_AUTO_HOSTS ""
ENV FLAP_DETECTION_ENABLED true
ENV FLAP_DETECTION_HALF_LIFE_SECONDS 60.0
ENV FLAP_DETECTION_THRESHOLD 4.0
ENV FLAP_DETECTION_MINIMUM_SCORE 0.02
ENV LDAP_HOST ldap.forumsys.com
ENV LDAP_PORT 389
ENV LDAP_BASE_DN dc=example,dc=com
ENV LDAP_BIND_DN cn=read-only-admin,dc=example,dc=com
ENV LDAP_BIND_PASSWORD password
ENV LDAP_USER_FILTER (uid=%s)
ENV LDAP_USE_SSL false
ENV OAUTH_HOST openshift.default.svc.cluster.local
ENV OAUTH_CLIENT_ID openshift-challenging-client
ENV OAUTH_RESPONSE_TYPE token
ENV RETHINKDB_ADDRESS localhost:28015
ENV RETHINKDB_DATABASE golerta
ENV RETHINKDB_ALERT_HISTORY_LIMIT 100
ENV NOTIFIER_TRIGGER_SEVERITIES \"critical\",\"flapping\"
ENV FILE_NOTIFIER_ENABLED false
ENV PAGERDUTY_NOTIFIER_ENABLED false
ENV PAGERDUTY_SERVICE_KEY CHANGEME
ENV EMAIL_NOTIFIER_ENABLED false
ENV EMAIL_TO \"test1@localhost\"
ENV EMAIL_FROM golerta@localhost
ENV EMAIL_SMTP_SERVER localhost
ENV EMAIL_SMTP_USER test1@localhost
ENV EMAIL_SMTP_PASSWORD password
ENV EMAIL_SKIP_SSL_VERIFY true
ENV EMAIL_SMTP_PORT 25
ENV EMAIL_GOLERTA_URL http://localhost:5608

CMD dockerize \
-template ./golerta.tmpl:./golerta.toml \
./golerta server --config ./golerta.toml
COPY --from=build /go/src/github.com/allen13/golerta/golerta /golerta
COPY --from=build /go/src/github.com/allen13/golerta/static /static
# Might need this later
# ADD https://curl.haxx.se/ca/cacert.pem /etc/ssl/certs/ca-certificates.crt
CMD ["/golerta", "server"]
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ features
* IN DEVELOPMENT: Fully distributed - Currently the continuous queries can only be run on a single node without duplicating effort.


configuration
-------------

Golerta uses [Viper](https://github.com/spf13/viper) for configuration. This supports a wide variety of formats, including JSON, YAML, TOML, and HCL. See docker-example/example.toml for an example configuration. In addition to a config file, environment variables can be set to match the configuration. Variables are prefixed with GOLERTA_, followed by the main section (such as LDAP_), then the value (all together GOLERTA_LDAP_HOST). For example, the parent app structure would look like the following JSON ```{"app": {"bind_addr": 5608, "signing_key": "super_secret_signing_key"}}```, the equivalent environment variable is GOLERTA_APP_BIND_ADDR. This is very useful for docker containers.


docker image
------------
Example: Run golerta minimal
Expand All @@ -28,7 +34,16 @@ Example: Run golerta minimal

Example: Run golerta by linking to both the rethinkdb and smtp service containers.

docker run -p 5608:5608 --link rethinkdb:rethinkdb --link smtp:smtp -e RETHINKDB_ADDRESS=rethinkdb:28015 -e EMAIL_NOTIFIER_ENABLED=true -e EMAIL_SMTP_SERVER=smtp golerta
docker run -p 5608:5608 --link rethinkdb:rethinkdb --link smtp:smtp -e GOLERTA_RETHINKDB_ADDRESS=rethinkdb:28015 -e GOLERTA_EMAIL_NOTIFIER_ENABLED=true -e GOLERTA_EMAIL_SMTP_SERVER=smtp golerta

Example: Using composer for a full tick stack, including an example toml file

cd docker-compose.yml
docker-compose up -d

Example: Getting an agent auth token (where $GOLERTA is the docker container ID or name) from a docker container

docker exec -it $GOLERTA /golerta createAgentToken gauss

development environment
-----------------------
Expand All @@ -55,4 +70,5 @@ Run all unit tests:

go test ./app/...

If RethinkDB is not available, or relevant to the given tests, SKIP_RETHINKDB=true can be set to skip database related tests.

8 changes: 4 additions & 4 deletions app/algorithms/flap_detection.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import (
)

type FlapDetection struct {
Enabled bool `toml:"enabled"`
Enabled bool `mapstructure:"enabled"`

//How many seconds does it take for a timestamp to reach 0.5 flapscore
HalfLifeSeconds float64 `toml:"half_life_seconds"`
HalfLifeSeconds float64 `mapstructure:"half_life_seconds"`

//Flap score at which the alert is considered to be flapping
Threshold float64 `toml:"threshold"`
Threshold float64 `mapstructure:"threshold"`

//individual severity time change score threshold at which a severity time change is dropped from history
MinimumScore float64 `toml:"minimum_score"`
MinimumScore float64 `mapstructure:"minimum_score"`
}

func (f *FlapDetection) Init() {
Expand Down
4 changes: 2 additions & 2 deletions app/algorithms/flap_detection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ func TestFlapDetection_Detect(t *testing.T) {
isFlapping, flapScore, remainingSeverityTimeChanges := f.Detect(severityTimeChanges)

if !isFlapping {
t.Errorf("should be flapping")
t.Error("should be flapping")
}

if flapScore < 0.9 {
t.Error("flap score should be > 0.9\nflapScore: %f", flapScore)
t.Errorf("flap score should be > 0.9\nflapScore: %f", flapScore)
}

if len(remainingSeverityTimeChanges) != 1 {
Expand Down
32 changes: 24 additions & 8 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package app

import (
"log"

"github.com/labstack/echo"
echoMiddleware "github.com/labstack/echo/middleware"

"github.com/allen13/golerta/app/auth"
"github.com/allen13/golerta/app/auth/middleware"
"github.com/allen13/golerta/app/config"
"github.com/allen13/golerta/app/controllers"
"github.com/allen13/golerta/app/services"
"github.com/labstack/echo"
"log"
)

func BuildApp(config config.GolertaConfig) (e *echo.Echo) {
Expand All @@ -22,19 +25,30 @@ func BuildApp(config config.GolertaConfig) (e *echo.Echo) {

continuousQueryService := &services.ContinuousQueryService{
DB: db,
QueryInterval: config.Golerta.ContinuousQueryInterval.Duration,
QueryInterval: config.App.ContinuousQueryInterval.Duration,
Notifiers: config.Notifiers,
FlapDetection: &config.FlapDetection,
}
go continuousQueryService.Start()

e = echo.New()

// enable CORS if UI is detached from the golerta process
e.Use(echoMiddleware.CORS())

authProvider := BuildAuthProvider(config)

shouldSkipAuth := func(_ echo.Context) bool {
c := config.App.AuthProvider == "noop"
return c
}

authMiddleware := middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte(config.Golerta.SigningKey),
Skipper: shouldSkipAuth,
SigningKey: []byte(config.App.SigningKey),
TokenLookup: "header:Authorization,query:api-key",
})

authController := controllers.AuthController{
Echo: e,
AuthProvider: authProvider,
Expand All @@ -49,7 +63,7 @@ func BuildApp(config config.GolertaConfig) (e *echo.Echo) {
Echo: e,
AlertService: alertsService,
AuthMiddleware: authMiddleware,
LogAlertRequests: config.Golerta.LogAlertRequests,
LogAlertRequests: config.App.LogAlertRequests,
}
alertsController.Init()

Expand All @@ -62,11 +76,13 @@ func BuildApp(config config.GolertaConfig) (e *echo.Echo) {
}

func BuildAuthProvider(config config.GolertaConfig) (authProvider auth.AuthProvider) {
switch config.Golerta.AuthProvider {
switch config.App.AuthProvider {
case "ldap":
authProvider = &config.Ldap
case "oauth":
authProvider = &config.OAuth
case "noop":
authProvider = &config.Noop
}

err := authProvider.Connect()
Expand All @@ -75,9 +91,9 @@ func BuildAuthProvider(config config.GolertaConfig) (authProvider auth.AuthProvi
if err != nil {
log.Fatal(err)
}
if config.Golerta.SigningKey == "" {
if config.App.SigningKey == "" {
log.Fatal("Shutting down, signing key must be provided.")
}
authProvider.SetSigningKey(config.Golerta.SigningKey)
authProvider.SetSigningKey(config.App.SigningKey)
return
}
16 changes: 8 additions & 8 deletions app/auth/ldap/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import (
type LDAPAuthProvider struct {
conn *ldap.Conn
signingKey string
Host string `toml:"host"`
Port int `toml:"port"`
UseSSL bool `toml:"use_ssl"`
BaseDN string `toml:"base_dn"`
BindDN string `toml:"bind_dn"`
BindPassword string `toml:"bind_password"`
UserFilter string `toml:"user_filter"`
Attributes []string `toml:"attributes"`
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
UseSSL bool `mapstructure:"use_ssl"`
BaseDN string `mapstructure:"base_dn"`
BindDN string `mapstructure:"bind_dn"`
BindPassword string `mapstructure:"bind_password"`
UserFilter string `mapstructure:"user_filter"`
Attributes []string `mapstructure:"attributes"`
}

func (lc *LDAPAuthProvider) SetSigningKey(key string) {
Expand Down
16 changes: 16 additions & 0 deletions app/auth/middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
type (
// JWTConfig defines the config for JWT middleware.
JWTConfig struct {
// Skipper defines a function to skip middleware.
Skipper Skipper

// Signing key to validate token.
// Required.
SigningKey interface{} `json:"signing_key"`
Expand Down Expand Up @@ -39,6 +42,8 @@ type (
}

jwtExtractor func(echo.Context) (string, error)

Skipper func(c echo.Context) bool
)

const (
Expand All @@ -53,6 +58,7 @@ const (
var (
// DefaultJWTConfig is the default JWT auth middleware config.
DefaultJWTConfig = JWTConfig{
Skipper: DefaultSkipper,
SigningMethod: AlgorithmHS256,
ContextKey: "user",
TokenLookup: "header:" + echo.HeaderAuthorization,
Expand All @@ -78,6 +84,9 @@ func JWT(key []byte) echo.MiddlewareFunc {
// See: `JWT()`.
func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
// Defaults
if config.Skipper == nil {
config.Skipper = DefaultJWTConfig.Skipper
}
if config.SigningKey == nil {
panic("jwt middleware requires signing key")
}
Expand All @@ -99,6 +108,9 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {

return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if config.Skipper(c) {
return next(c)
}

auth, err := extractor(c)
if err != nil {
Expand Down Expand Up @@ -193,3 +205,7 @@ func jwtFromExtractors(extractors []jwtExtractor) jwtExtractor {
return "", errors.New(extractorErrors)
}
}

func DefaultSkipper(echo.Context) bool {
return false
}
27 changes: 27 additions & 0 deletions app/auth/noop/noop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package noop

type NoopAuthProvider struct {
signingKey string
}

func (na *NoopAuthProvider) SetSigningKey(_ string) {
na.signingKey = ""
}

// Connect bypassed for no auth provider
func (na *NoopAuthProvider) Connect() error {
return nil
}

// Close bypassed for no auth provider
func (na *NoopAuthProvider) Close() {
return
}

// Authenticate returns true to noop the auth provider
func (na *NoopAuthProvider) Authenticate(_ string, _ string) (authenticated bool, token string, err error) {
token = ""
authenticated = true
err = nil
return
}
6 changes: 3 additions & 3 deletions app/auth/oauth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
)

type OAuthAuthProvider struct {
Host string `toml:"host"`
ClientID string `toml:"client_id"`
ResponseType string `toml:"response_type"`
Host string `mapstructure:"host"`
ClientID string `mapstructure:"client_id"`
ResponseType string `mapstructure:"response_type"`
signingKey string
}

Expand Down
Loading