Skip to content

Commit

Permalink
Merge pull request #13 from alexandreh2ag/refactor_server_http
Browse files Browse the repository at this point in the history
Refactor how start http server
  • Loading branch information
alexandreh2ag authored Jan 26, 2025
2 parents 67f97b2 + ac9f95d commit b35e901
Show file tree
Hide file tree
Showing 18 changed files with 201 additions and 68 deletions.
20 changes: 13 additions & 7 deletions apps/agent/cli/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import (
stdContext "context"
"fmt"
"github.com/alexandreh2ag/lets-go-tls/apps/agent/context"
"github.com/alexandreh2ag/lets-go-tls/apps/agent/http"
appAgentHttp "github.com/alexandreh2ag/lets-go-tls/apps/agent/http"
"github.com/alexandreh2ag/lets-go-tls/apps/agent/service"
appHttp "github.com/alexandreh2ag/lets-go-tls/http"
"github.com/spf13/cobra"
)

Expand All @@ -20,16 +21,21 @@ func GetStartCmd(ctx *context.AgentContext) *cobra.Command {
func GetStartRunFn(ctx *context.AgentContext) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {

e, err := http.CreateServerHTTP(ctx)
if err != nil {
return err
e := appAgentHttp.CreateServerHTTP(ctx)

httpConfig := ctx.Config.HTTP
go appHttp.StartServerHTTP(e, httpConfig.Listen, nil)

if httpConfig.TLS.Enable {
tlsConfig := appHttp.CreateTLSConfig(httpConfig.TLS)
go appHttp.StartServerHTTP(e, httpConfig.TLS.Listen, tlsConfig)
}

srv := service.NewService(ctx)
go func() {
err = srv.Start(ctx)
if err != nil {
panic(err)
errStart := srv.Start(ctx)
if errStart != nil {
panic(errStart)
}
}()

Expand Down
28 changes: 27 additions & 1 deletion apps/agent/cli/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"time"
)

func TestGetStartRunFn_Success(t *testing.T) {
func TestGetStartRunFn_SuccessOnlyListenHTTP(t *testing.T) {
ctx := context.TestContext(nil)
ctx.Config.HTTP.Listen = "127.0.0.1:0"
viper.Reset()
Expand All @@ -37,3 +37,29 @@ func TestGetStartRunFn_Success(t *testing.T) {
time.Sleep(time.Millisecond * 100)
ctx.Signal() <- syscall.SIGINT
}

func TestGetStartRunFn_SuccessListenHTTPS(t *testing.T) {
ctx := context.TestContext(nil)
ctx.Config.HTTP.Listen = "127.0.0.1:0"
ctx.Config.HTTP.TLS.Enable = true
ctx.Config.HTTP.TLS.Listen = "127.0.0.1:0"
viper.Reset()
viper.SetFs(ctx.Fs)

ctrl := gomock.NewController(t)
defer ctrl.Finish()
storage := mockTypesStorageState.NewMockStorage(ctrl)
storage.EXPECT().Load().AnyTimes().Return(&types.State{}, nil)
storage.EXPECT().Save(gomock.Any()).AnyTimes().Return(nil)
ctx.StateStorage = storage

ctx.MetricsRegister = appProm.NewRegistry(types.NameServerMetrics, prometheus.NewRegistry())

cmd := GetStartCmd(ctx)
go func() {
err := GetStartRunFn(ctx)(cmd, []string{})
assert.NoError(t, err)
}()
time.Sleep(time.Millisecond * 100)
ctx.Signal() <- syscall.SIGINT
}
13 changes: 2 additions & 11 deletions apps/agent/http/server.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package http

import (
"fmt"
"github.com/alexandreh2ag/lets-go-tls/apps/agent/context"
"github.com/alexandreh2ag/lets-go-tls/apps/agent/http/controller"
"github.com/alexandreh2ag/lets-go-tls/apps/agent/http/middleware"
"github.com/alexandreh2ag/lets-go-tls/http"
"github.com/labstack/echo-contrib/echoprometheus"
"github.com/labstack/echo/v4"
buildinHttp "net/http"
)

func CreateServerHTTP(ctx *context.AgentContext) (*echo.Echo, error) {
func CreateServerHTTP(ctx *context.AgentContext) *echo.Echo {
e := http.CreateEcho()

if ctx.Config.HTTP.MetricsEnable {
Expand All @@ -25,12 +23,5 @@ func CreateServerHTTP(ctx *context.AgentContext) (*echo.Echo, error) {
e.Use(middleware.HandlerContext(ctx))
e.GET(http.GetApiPrefix(http.AgentApiRequests), controller.GetRequests)

go func() {
err := e.Start(ctx.Config.HTTP.Listen)
if err != nil && err != buildinHttp.ErrServerClosed {
panic(fmt.Errorf("fail to start http server with %v", err))
}

}()
return e, nil
return e
}
3 changes: 1 addition & 2 deletions apps/agent/http/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ func TestCreateServerHTTP(t *testing.T) {
ctx.Config.HTTP.Listen = "127.0.0.1:0"
ctx.Config.HTTP.MetricsEnable = true

got, err := CreateServerHTTP(ctx)
got := CreateServerHTTP(ctx)
time.Sleep(200 * time.Millisecond)
assert.NoError(t, err)
assert.NotNil(t, got)
}
20 changes: 13 additions & 7 deletions apps/server/cli/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"fmt"
"github.com/alexandreh2ag/lets-go-tls/apps/server/acme"
"github.com/alexandreh2ag/lets-go-tls/apps/server/context"
"github.com/alexandreh2ag/lets-go-tls/apps/server/http"
appSrvHttp "github.com/alexandreh2ag/lets-go-tls/apps/server/http"
"github.com/alexandreh2ag/lets-go-tls/apps/server/manager"
appHttp "github.com/alexandreh2ag/lets-go-tls/http"
"github.com/spf13/cobra"
)

Expand All @@ -21,17 +22,22 @@ func GetStartCmd(ctx *context.ServerContext) *cobra.Command {
func GetStartRunFn(ctx *context.ServerContext) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {

e, err := http.CreateServerHTTP(ctx, acme.GetHTTPProvider(ctx))
if err != nil {
return err
e := appSrvHttp.CreateServerHTTP(ctx, acme.GetHTTPProvider(ctx))

httpConfig := ctx.Config.HTTP
go appHttp.StartServerHTTP(e, httpConfig.Listen, nil)

if httpConfig.TLS.Enable {
tlsConfig := appHttp.CreateTLSConfig(httpConfig.TLS)
go appHttp.StartServerHTTP(e, httpConfig.TLS.Listen, tlsConfig)
}

mgr, _ := manager.CreateManager(ctx)

go func() {
err = mgr.Start(ctx)
if err != nil {
panic(err)
errStart := mgr.Start(ctx)
if errStart != nil {
panic(errStart)
}
}()

Expand Down
30 changes: 29 additions & 1 deletion apps/server/cli/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"time"
)

func TestGetStartRunFn_Success(t *testing.T) {
func TestGetStartRunFn_SuccessOnlyListenHTTP(t *testing.T) {
ctx := context.TestContext(nil)
ctx.Config.HTTP.Listen = "127.0.0.1:0"
viper.Reset()
Expand All @@ -41,3 +41,31 @@ func TestGetStartRunFn_Success(t *testing.T) {
time.Sleep(time.Millisecond * 100)
ctx.Signal() <- syscall.SIGINT
}

func TestGetStartRunFn_SuccessListenHTTPS(t *testing.T) {
ctx := context.TestContext(nil)
ctx.Config.HTTP.Listen = "127.0.0.1:0"
ctx.Config.HTTP.TLS.Enable = true
ctx.Config.HTTP.TLS.Listen = "127.0.0.1:0"
viper.Reset()
viper.SetFs(ctx.Fs)

ctrl := gomock.NewController(t)
defer ctrl.Finish()
storage := mockTypesStorageState.NewMockStorage(ctrl)
account, _ := acme.NewAccount("foo@bar.com")
account.Registration = &registration.Resource{}
storage.EXPECT().Load().AnyTimes().Return(&types.State{Account: account}, nil)
storage.EXPECT().Save(gomock.Any()).AnyTimes().Return(nil)
ctx.StateStorage = storage

ctx.MetricsRegister = appProm.NewRegistry(types.NameServerMetrics, prometheus.NewRegistry())

cmd := GetStartCmd(ctx)
go func() {
err := GetStartRunFn(ctx)(cmd, []string{})
assert.NoError(t, err)
}()
time.Sleep(time.Millisecond * 100)
ctx.Signal() <- syscall.SIGINT
}
17 changes: 2 additions & 15 deletions apps/server/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import (
"github.com/labstack/echo-contrib/echoprometheus"
echojwt "github.com/labstack/echo-jwt/v4"
"github.com/labstack/echo/v4"
buildinHttp "net/http"
)

const (
AcmeEndpoint = "/.well-known/acme-challenge"
)

func CreateServerHTTP(ctx *context.ServerContext, httpProvider *acmeHttp.ChallengeHTTP) (*echo.Echo, error) {
func CreateServerHTTP(ctx *context.ServerContext, httpProvider *acmeHttp.ChallengeHTTP) *echo.Echo {
e := http.CreateEcho()

if ctx.Config.HTTP.MetricsEnable {
Expand All @@ -41,17 +40,5 @@ func CreateServerHTTP(ctx *context.ServerContext, httpProvider *acmeHttp.Challen
))
authorizedGroup.POST(http.GetApiPrefix(http.ServerApiGetCertificates), controller.GetCertificatesFromRequests)

go func() {
var err error
if ctx.Config.HTTP.TLS.Enable {
err = e.StartTLS(ctx.Config.HTTP.Listen, ctx.Config.HTTP.TLS.CertPath, ctx.Config.HTTP.TLS.KeyPath)
} else {
err = e.Start(ctx.Config.HTTP.Listen)
}
if err != nil && err != buildinHttp.ErrServerClosed {
panic(fmt.Errorf("fail to start http server with %v", err))
}
}()

return e, nil
return e
}
22 changes: 1 addition & 21 deletions apps/server/http/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
"testing"
"time"
)

func TestCreateServerHTTP(t *testing.T) {
Expand All @@ -17,25 +16,6 @@ func TestCreateServerHTTP(t *testing.T) {
ctx.Config.HTTP.MetricsEnable = true
ctx.MetricsRegister = appProm.NewRegistry(types.NameServerMetrics, prometheus.NewRegistry())
httpProvider := http.NewChallenge(ctx.Logger, ctx.Cache)
got, err := CreateServerHTTP(ctx, httpProvider)
time.Sleep(200 * time.Millisecond)
assert.NoError(t, err)
got := CreateServerHTTP(ctx, httpProvider)
assert.NotNil(t, got)
}

func TestCreateServerHTTPWithTLS_Fail(t *testing.T) {
ctx := appCtx.TestContext(nil)
ctx.Config.HTTP.Listen = "127.0.0.1:0"
ctx.Config.HTTP.MetricsEnable = true
ctx.MetricsRegister = appProm.NewRegistry(types.NameServerMetrics, prometheus.NewRegistry())
ctx.Config.HTTP.TLS.Enable = true
ctx.Config.HTTP.TLS.CertPath = "./fixtures/cert.crt"
ctx.Config.HTTP.TLS.KeyPath = "./fixtures/priv.key"
httpProvider := http.NewChallenge(ctx.Logger, ctx.Cache)

got, err := CreateServerHTTP(ctx, httpProvider)
time.Sleep(200 * time.Millisecond)
assert.NoError(t, err)
assert.NotNil(t, got)

}
1 change: 1 addition & 0 deletions config/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type HTTPConfig struct {

type TLSConfig struct {
Enable bool `mapstructure:"enable"`
Listen string `mapstructure:"listen" validate:"required_if=Enable true"`
CertPath string `mapstructure:"cert_path" validate:"required_if=Enable true"`
KeyPath string `mapstructure:"key_path" validate:"required_if=Enable true"`
}
11 changes: 10 additions & 1 deletion context/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"time"
)

func TestDefaultContext(t *testing.T) {
func TestDefaultContext_Success(t *testing.T) {

level := &slog.LevelVar{}
level.Set(slog.LevelInfo)
Expand All @@ -38,6 +38,15 @@ func TestDefaultContext(t *testing.T) {
assert.Equal(t, want, got)
}

func TestDefaultContext_FailGetwd(t *testing.T) {
dir, _ := os.MkdirTemp("", "")
_ = os.Chdir(dir)
_ = os.RemoveAll(dir)
assert.Panics(t, func() {
DefaultContext()
})
}

func TestTestContext(t *testing.T) {

level := &slog.LevelVar{}
Expand Down
3 changes: 2 additions & 1 deletion docs/agent_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
```yaml
interval: 5m0s # duration each process to fetch certificates. default: 5m
http:
listen: 0.0.0.0:8080 # server listen address. default: 0.0.0.0:8080
listen: 0.0.0.0:8080 # http server listen address. default: 0.0.0.0:8080
metrics_enable: false # enable metrics on path `/metrics`. default: false
tls:
enable: false
listen: 0.0.0.0:443 # https server listen address.
cert_path: "/ssl/certificate.crt" # mandatory only when enable is true
key_path: "/ssl/private.key" # mandatory only when enable is true
manager:
Expand Down
3 changes: 2 additions & 1 deletion docs/server_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ interval: 5m0s # duration each process to fetch requesters and obtain certificat
lock_duration: 25m0s # max duration to lock process to obtain or renew certificate to prevent concurrency. default: 25m
unused_retention: 336h0m0s # time to keep in store unused certificate. default: 14 days
http:
listen: 0.0.0.0:8080 # server listen address. default: 0.0.0.0:8080
listen: 0.0.0.0:8080 # http server listen address. default: 0.0.0.0:8080
metrics_enable: false # enable metrics on path `/metrics`. default: false
tls:
enable: false
listen: 0.0.0.0:443 # https server listen address.
cert_path: "/ssl/certificate.crt" # mandatory only when enable is true
key_path: "/ssl/private.key" # mandatory only when enable is true
jwt:
Expand Down
1 change: 1 addition & 0 deletions examples/agent.cfg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ http:
cert_path: ""
enable: false
key_path: ""
listen: ""
interval: 5m0s
manager:
address: 127.0.0.1:8080
Expand Down
1 change: 1 addition & 0 deletions examples/server.cfg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ http:
cert_path: ""
enable: false
key_path: ""
listen: ""
interval: 5m0s
jwt:
key: superSecret
Expand Down
File renamed without changes.
File renamed without changes.
33 changes: 33 additions & 0 deletions http/server.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package http

import (
"crypto/tls"
"fmt"
"github.com/alexandreh2ag/lets-go-tls/config"
"github.com/labstack/echo/v4"
echoMiddleware "github.com/labstack/echo/v4/middleware"
buildinHttp "net/http"
)

const (
Expand All @@ -27,3 +30,33 @@ func CreateEcho() *echo.Echo {

return e
}

func CreateTLSConfig(tlsConfig config.TLSConfig) *tls.Config {
return &tls.Config{
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
cert, errLoadCert := tls.LoadX509KeyPair(tlsConfig.CertPath, tlsConfig.KeyPath)
if errLoadCert != nil {
return nil, errLoadCert
}
return &cert, nil
},
}
}

func StartServerHTTP(e *echo.Echo, listen string, tlsConfig *tls.Config) {
server := buildinHttp.Server{
Addr: listen,
Handler: e,
}

var errStart error
if tlsConfig != nil {
server.TLSConfig = tlsConfig
errStart = server.ListenAndServeTLS("", "")
} else {
errStart = server.ListenAndServe()
}
if errStart != nil && errStart != buildinHttp.ErrServerClosed {
panic(fmt.Errorf("fail to start http server with %v", errStart))
}
}
Loading

0 comments on commit b35e901

Please sign in to comment.