3
0

Config. environment (throughenv var 'ENVIRONMENT')

This commit is contained in:
Denis Arh
2020-11-04 14:38:07 +01:00
parent 7666fe2d62
commit ed8fc547f7
12 changed files with 106 additions and 76 deletions

View File

@@ -6,20 +6,21 @@ import (
type (
Options struct {
ActionLog options.ActionLogOpt
SMTP options.SMTPOpt
Auth options.AuthOpt
HTTPClient options.HTTPClientOpt
DB options.DBOpt
Upgrade options.UpgradeOpt
Provision options.ProvisionOpt
Sentry options.SentryOpt
ObjStore options.ObjectStoreOpt
Corredor options.CorredorOpt
Monitor options.MonitorOpt
WaitFor options.WaitForOpt
HTTPServer options.HTTPServerOpt
Websocket options.WebsocketOpt
Environment options.EnvironmentOpt
ActionLog options.ActionLogOpt
SMTP options.SMTPOpt
Auth options.AuthOpt
HTTPClient options.HTTPClientOpt
DB options.DBOpt
Upgrade options.UpgradeOpt
Provision options.ProvisionOpt
Sentry options.SentryOpt
ObjStore options.ObjectStoreOpt
Corredor options.CorredorOpt
Monitor options.MonitorOpt
WaitFor options.WaitForOpt
HTTPServer options.HTTPServerOpt
Websocket options.WebsocketOpt
}
)
@@ -29,20 +30,23 @@ func NewOptions(prefix ...string) *Options {
p = prefix[0]
}
// @todo remover prefixes on opt constructors and
// pass in EnvironmentOpt so we can have environment-dependant defaults
return &Options{
ActionLog: *options.ActionLog(),
Auth: *options.Auth(),
SMTP: *options.SMTP(p),
HTTPClient: *options.HttpClient(p),
DB: *options.DB(p),
Upgrade: *options.Upgrade(p),
Provision: *options.Provision(p),
Sentry: *options.Sentry(p),
ObjStore: *options.ObjectStore(p),
Corredor: *options.Corredor(),
Monitor: *options.Monitor(p),
WaitFor: *options.WaitFor(p),
HTTPServer: *options.HTTP(p),
Websocket: *options.Websocket(p),
Environment: *options.Environment(),
ActionLog: *options.ActionLog(),
Auth: *options.Auth(),
SMTP: *options.SMTP(p),
HTTPClient: *options.HttpClient(p),
DB: *options.DB(p),
Upgrade: *options.Upgrade(p),
Provision: *options.Provision(p),
Sentry: *options.Sentry(p),
ObjStore: *options.ObjectStore(p),
Corredor: *options.Corredor(),
Monitor: *options.Monitor(p),
WaitFor: *options.WaitFor(p),
HTTPServer: *options.HTTP(p),
Websocket: *options.Websocket(p),
}
}

View File

@@ -18,7 +18,7 @@ func (app *CortezaApp) Serve(ctx context.Context) (err error) {
{
// @todo refactor wait-for out of HTTP API server.
app.HttpServer = server.New(app.Log, app.Opt.HTTPServer, app.Opt.WaitFor)
app.HttpServer = server.New(app.Log, app.Opt.Environment, app.Opt.HTTPServer, app.Opt.WaitFor)
app.HttpServer.MountRoutes(app.mountHttpRoutes)
wg.Add(1)

View File

@@ -9,20 +9,16 @@ import (
type ctxKeyDebug struct{}
// Packs remote address to context
func DebugToContext(next http.Handler) http.Handler {
if true {
// debug disabled
return next
func DebugToContext(production bool) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
next.ServeHTTP(w, req.WithContext(context.WithValue(req.Context(), ctxKeyDebug{}, !production)))
})
}
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
next.ServeHTTP(w, req.WithContext(context.WithValue(req.Context(), ctxKeyDebug{}, true)))
})
}
// DebugFromContext returns remote IP address from context
func DebugFromContext(ctx context.Context) bool {
return true
debug, ok := ctx.Value(ctxKeyDebug{}).(bool)
return ok && debug
}

View File

@@ -96,7 +96,7 @@ func encode(w http.ResponseWriter, r *http.Request, payload interface{}) {
_ = err.Apply(errors.StackTrimAtFn("http.HandlerFunc.ServeHTTP"))
}
errors.ServeHTTP(w, r, err, DebugFromContext(r.Context()))
errors.ServeHTTP(w, r, err, !DebugFromContext(r.Context()))
}
w.Header().Set("Content-Type", "application/json")

View File

@@ -2,24 +2,22 @@ package server
import (
"github.com/cortezaproject/corteza-server/pkg/api"
"github.com/cortezaproject/corteza-server/pkg/logger"
"github.com/getsentry/sentry-go/http"
"github.com/go-chi/chi/middleware"
"go.uber.org/zap"
"net/http"
"os"
"runtime/debug"
"github.com/go-chi/chi/middleware"
"go.uber.org/zap"
"github.com/getsentry/sentry-go/http"
"github.com/cortezaproject/corteza-server/pkg/logger"
)
func BaseMiddleware(log *zap.Logger) []func(http.Handler) http.Handler {
func BaseMiddleware(isProduction bool, log *zap.Logger) []func(http.Handler) http.Handler {
return []func(http.Handler) http.Handler{
handleCORS,
middleware.RealIP,
api.RemoteAddrToContext,
middleware.RequestID,
api.DebugToContext(isProduction),
contextLogger(log),
}
}

View File

@@ -16,19 +16,22 @@ import (
type (
server struct {
log *zap.Logger
httpOpt options.HTTPServerOpt
waitForOpt options.WaitForOpt
endpoints []func(r chi.Router)
log *zap.Logger
httpOpt options.HTTPServerOpt
waitForOpt options.WaitForOpt
environmentOpt options.EnvironmentOpt
endpoints []func(r chi.Router)
}
)
func New(log *zap.Logger, httpOpt options.HTTPServerOpt, waitForOpt options.WaitForOpt) *server {
func New(log *zap.Logger, envOpt options.EnvironmentOpt, httpOpt options.HTTPServerOpt, waitForOpt options.WaitForOpt) *server {
return &server{
endpoints: make([]func(r chi.Router), 0),
log: log.Named("http"),
httpOpt: httpOpt,
waitForOpt: waitForOpt,
endpoints: make([]func(r chi.Router), 0),
log: log.Named("http"),
environmentOpt: envOpt,
httpOpt: httpOpt,
waitForOpt: waitForOpt,
}
}
@@ -48,7 +51,7 @@ func (s server) Serve(ctx context.Context) {
router := chi.NewRouter()
// Base middleware, CORS, RealIP, RequestID, context-logger
router.Use(BaseMiddleware(s.log)...)
router.Use(BaseMiddleware(s.environmentOpt.IsProduction(), s.log)...)
router.Group(func(r chi.Router) {
s.bindMiscRoutes(r)

View File

@@ -12,7 +12,7 @@ import (
// ServeHTTP Prepares and encodes given error for HTTP transport
//
// mask arg hides extra/debug info
func ServeHTTP(w http.ResponseWriter, r *http.Request, err error, debug bool) {
func ServeHTTP(w http.ResponseWriter, r *http.Request, err error, mask bool) {
var (
// Very naive approach on parsing accept headers
acceptsJson = strings.Contains(r.Header.Get("accept"), "application/json")
@@ -31,12 +31,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, err error, debug bool) {
w.WriteHeader(code)
if !debug {
// trim error details when not debugging
err = fmt.Errorf(err.Error())
}
if debug && !acceptsJson {
if !mask && !acceptsJson {
// Prettify error for plain text debug output
w.Header().Set("Content-Type", "plain/text")
writeHttpPlain(w, err)
@@ -46,7 +41,7 @@ func ServeHTTP(w http.ResponseWriter, r *http.Request, err error, debug bool) {
}
w.Header().Set("Content-Type", "application/json")
writeHttpJSON(w, err)
writeHttpJSON(w, err, mask)
}
func writeHttpPlain(w io.Writer, err error) {
@@ -97,14 +92,20 @@ func writeHttpPlain(w io.Writer, err error) {
}
func writeHttpJSON(w io.Writer, err error) {
func writeHttpJSON(w io.Writer, err error, mask bool) {
var (
wrap = struct {
Error interface{} `json:"error"`
}{}
)
if c, is := err.(*Error); is {
if se, is := err.(interface{ Safe() bool }); !is || !se.Safe() {
// trim error details when not debugging or error is not safe
err = fmt.Errorf(err.Error())
}
if c, is := err.(json.Marshaler); is {
// take advantage of JSON marshaller on error
wrap.Error = c
} else {
wrap.Error = map[string]string{"message": err.Error()}

View File

@@ -11,12 +11,10 @@ func ExampleSimpleErrorAsText() {
// Output:
// Error: dummy error
// --------------------------------------------------------------------------------
// Note: you are seeing this because system is running in development mode
// and HTTP request is made without "Accept: .../json" headers
}
func ExampleSimpleErrorAsJson() {
writeHttpJSON(os.Stdout, fmt.Errorf("dummy error"))
writeHttpJSON(os.Stdout, fmt.Errorf("dummy error"), true)
// Output:
// {"error":{"message":"dummy error"}}
@@ -31,14 +29,12 @@ func ExampleErrorAsText() {
// --------------------------------------------------------------------------------
// a: b
// --------------------------------------------------------------------------------
// Note: you are seeing this because system is running in development mode
// and HTTP request is made without "Accept: .../json" headers
}
func ExampleErrorAsJson() {
err := New(0, "dummy error", Meta("a", "b"), Meta(&Error{}, "nope"))
err.stack = nil // will not test the stack as file path & line numbers might change
writeHttpJSON(os.Stdout, err)
writeHttpJSON(os.Stdout, err, false)
// Output:
// {"error":{"message":"dummy error","meta":{"a":"b"}}}

View File

@@ -0,0 +1,32 @@
package options
import "strings"
type (
EnvironmentOpt struct {
Environment string `env:"ENVIRONMENT"`
}
)
func Environment() (o *EnvironmentOpt) {
o = &EnvironmentOpt{
Environment: "production",
}
fill(o)
return
}
func (e EnvironmentOpt) IsDevelopment() bool {
return strings.HasPrefix(e.Environment, "dev")
}
func (e EnvironmentOpt) IsTest() bool {
return strings.HasPrefix(e.Environment, "test")
}
func (e EnvironmentOpt) IsProduction() bool {
return !e.IsDevelopment() &&
!e.IsTest()
}

View File

@@ -68,7 +68,7 @@ func InitTestApp() {
if r == nil {
r = chi.NewRouter()
r.Use(server.BaseMiddleware(logger.Default())...)
r.Use(server.BaseMiddleware(false, logger.Default())...)
helpers.BindAuthMiddleware(r)
rest.MountRoutes(r)
}

View File

@@ -65,7 +65,7 @@ func InitTestApp() {
if r == nil {
r = chi.NewRouter()
r.Use(server.BaseMiddleware(logger.Default())...)
r.Use(server.BaseMiddleware(false, logger.Default())...)
helpers.BindAuthMiddleware(r)
rest.MountRoutes(r)
}

View File

@@ -83,7 +83,7 @@ func InitTestApp() {
if r == nil {
r = chi.NewRouter()
r.Use(server.BaseMiddleware(logger.Default())...)
r.Use(server.BaseMiddleware(false, logger.Default())...)
helpers.BindAuthMiddleware(r)
rest.MountRoutes(r)
}