Set up http server

- set up http server for a) handling the service requests and b)
serving the static assets for the ocis-web extension
- align the server command with other ocis-extensions, including config
variable naming
This commit is contained in:
Benedikt Kulmann
2020-07-01 11:05:32 +02:00
parent b58ddeeb62
commit 3f04adf4ff
8 changed files with 306 additions and 69 deletions
+74 -29
View File
@@ -2,14 +2,17 @@ package command
import (
"context"
"syscall"
"github.com/owncloud/ocis-accounts/pkg/flagset"
"os"
"os/signal"
"strings"
"github.com/micro/cli/v2"
"github.com/oklog/run"
"github.com/owncloud/ocis-accounts/pkg/config"
"github.com/owncloud/ocis-accounts/pkg/flagset"
"github.com/owncloud/ocis-accounts/pkg/metrics"
"github.com/owncloud/ocis-accounts/pkg/server/grpc"
"github.com/owncloud/ocis-accounts/pkg/server/http"
svc "github.com/owncloud/ocis-accounts/pkg/service/v0"
)
@@ -20,41 +23,83 @@ func Server(cfg *config.Config) *cli.Command {
Usage: "Start ocis accounts service",
Description: "uses an LDAP server as the storage backend",
Flags: flagset.ServerWithConfig(cfg),
Before: func(c *cli.Context) error {
return ParseConfig(c, cfg)
Before: func(ctx *cli.Context) error {
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
// When running on single binary mode the before hook from the root command won't get called. We manually
// call this before hook from ocis command, so the configuration can be loaded.
return ParseConfig(ctx, cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
gr := run.Group{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
service := grpc.NewService(
grpc.Logger(logger),
grpc.Context(ctx),
grpc.Config(cfg),
grpc.Name(cfg.Server.Name),
grpc.Namespace(cfg.Server.Namespace),
grpc.Address(cfg.Server.Address),
grpc.Flags(flagset.RootWithConfig(config.New())),
var (
gr = run.Group{}
ctx, cancel = context.WithCancel(context.Background())
mtrcs = metrics.New()
)
gr.Add(func() error {
logger.Info().Str("service", service.Name()).Msg("Reporting settings bundle to account service")
go svc.RegisterSettingsBundles(&logger)
return service.Run()
}, func(err error) {
if err != nil {
logger.Error().Err(err).Msg("account service died")
} else {
defer cancel()
{
server := http.Server(
http.Logger(logger),
http.Name(cfg.Server.Name),
http.Context(ctx),
http.Config(cfg),
http.Metrics(mtrcs),
http.Flags(flagset.RootWithConfig(cfg)),
http.Flags(flagset.ServerWithConfig(cfg)),
)
gr.Add(server.Run, func(_ error) {
logger.Info().
Str("service", service.Name()).
Str("server", "http").
Msg("Shutting down server")
}
cancel()
})
cancel()
})
}
{
server := grpc.Server(
grpc.Logger(logger),
grpc.Name(cfg.Server.Name),
grpc.Context(ctx),
grpc.Config(cfg),
grpc.Metrics(mtrcs),
)
gr.Add(func() error {
logger.Info().Str("service", server.Name()).Msg("Reporting settings bundles to settings service")
go svc.RegisterSettingsBundles(&logger)
return server.Run()
}, func(_ error) {
logger.Info().
Str("server", "grpc").
Msg("Shutting down server")
cancel()
})
}
{
stop := make(chan os.Signal, 1)
gr.Add(func() error {
signal.Notify(stop, os.Interrupt)
<-stop
return nil
}, func(err error) {
close(stop)
cancel()
})
}
run.SignalHandler(ctx, syscall.SIGKILL)
return gr.Run()
},
}
+15
View File
@@ -24,6 +24,19 @@ type LDAPSchema struct {
Groups string
}
// HTTP defines the available http configuration.
type HTTP struct {
Addr string
Namespace string
Root string
}
// GRPC defines the available grpc configuration.
type GRPC struct {
Addr string
Namespace string
}
// Server configures a server.
type Server struct {
Name string
@@ -42,6 +55,8 @@ type Log struct {
// Config merges all Account config parameters.
type Config struct {
LDAP LDAP
HTTP HTTP
GRPC GRPC
Server Server
Log Log
}
+35 -20
View File
@@ -35,36 +35,51 @@ func RootWithConfig(cfg *config.Config) []cli.Flag {
// ServerWithConfig applies cfg to the root flagset
func ServerWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "http-namespace",
Value: "com.owncloud.web",
Usage: "Set the base namespace for the http namespace",
EnvVars: []string{"ACCOUNTS_HTTP_NAMESPACE"},
Destination: &cfg.HTTP.Namespace,
},
&cli.StringFlag{
Name: "http-addr",
Value: "localhost:9181",
Usage: "Address to bind http server",
EnvVars: []string{"ACCOUNTS_HTTP_ADDR"},
Destination: &cfg.HTTP.Addr,
},
&cli.StringFlag{
Name: "http-root",
Value: "/",
Usage: "Root path of http server",
EnvVars: []string{"ACCOUNTS_HTTP_ROOT"},
Destination: &cfg.HTTP.Root,
},
&cli.StringFlag{
Name: "grpc-namespace",
Value: "com.owncloud.api",
Usage: "Set the base namespace for the grpc namespace",
EnvVars: []string{"ACCOUNTS_GRPC_NAMESPACE"},
Destination: &cfg.GRPC.Namespace,
},
&cli.StringFlag{
Name: "grpc-addr",
Value: "localhost:9180",
Usage: "Address to bind grpc server",
EnvVars: []string{"ACCOUNTS_GRPC_ADDR"},
Destination: &cfg.GRPC.Addr,
},
&cli.StringFlag{
Name: "name",
Value: "accounts",
DefaultText: "accounts",
Usage: "service name",
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
},
&cli.StringFlag{
Name: "namespace",
Aliases: []string{"ns"},
Value: "com.owncloud.api",
DefaultText: "com.owncloud.api",
Usage: "namespace",
EnvVars: []string{"ACCOUNTS_NAMESPACE"},
Destination: &cfg.Server.Namespace,
},
&cli.StringFlag{
Name: "address",
Aliases: []string{"addr"},
Value: "localhost:9180",
DefaultText: "localhost:9180",
Usage: "service endpoint",
EnvVars: []string{"ACCOUNTS_ADDRESS"},
Destination: &cfg.Server.Address,
},
&cli.StringFlag{
Name: "accounts-data-path",
Value: "/var/tmp/ocis-accounts",
DefaultText: "/var/tmp/ocis-accounts",
Usage: "accounts folder",
EnvVars: []string{"ACCOUNTS_DATA_PATH"},
Destination: &cfg.Server.AccountsDataPath,
+22
View File
@@ -0,0 +1,22 @@
package metrics
var (
// Namespace defines the namespace for the defines metrics.
Namespace = "ocis"
// Subsystem defines the subsystem for the defines metrics.
Subsystem = "accounts"
)
// Metrics defines the available metrics of this service.
type Metrics struct {
// Counter *prometheus.CounterVec
}
// New initializes the available metrics.
func New() *Metrics {
m := &Metrics{
}
// TODO: implement metrics
return m
}
+8 -15
View File
@@ -5,6 +5,7 @@ import (
"github.com/micro/cli/v2"
"github.com/owncloud/ocis-accounts/pkg/config"
"github.com/owncloud/ocis-accounts/pkg/metrics"
"github.com/owncloud/ocis-pkg/v2/log"
)
@@ -14,11 +15,10 @@ type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Name string
Address string
Logger log.Logger
Context context.Context
Config *config.Config
Namespace string
Metrics *metrics.Metrics
Flags []cli.Flag
}
@@ -33,13 +33,6 @@ func newOptions(opts ...Option) Options {
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Name provides a name for the service.
func Name(val string) Option {
return func(o *Options) {
@@ -47,10 +40,10 @@ func Name(val string) Option {
}
}
// Address provides an address for the service.
func Address(val string) Option {
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Address = val
o.Logger = val
}
}
@@ -68,10 +61,10 @@ func Config(val *config.Config) Option {
}
}
// Namespace provides a function to set the namespace option.
func Namespace(val string) Option {
// Metrics provides a function to set the metrics option.
func Metrics(val *metrics.Metrics) Option {
return func(o *Options) {
o.Namespace = val
o.Metrics = val
}
}
+5 -5
View File
@@ -6,15 +6,15 @@ import (
"github.com/owncloud/ocis-pkg/v2/service/grpc"
)
// NewService initializes a new go-micro service ready to run
func NewService(opts ...Option) grpc.Service {
// Server initializes a new go-micro service ready to run
func Server(opts ...Option) grpc.Service {
options := newOptions(opts...)
service := grpc.NewService(
grpc.Name(options.Name),
grpc.Name(options.Config.Server.Name),
grpc.Context(options.Context),
grpc.Address(options.Address),
grpc.Namespace(options.Namespace),
grpc.Address(options.Config.GRPC.Addr),
grpc.Namespace(options.Config.GRPC.Namespace),
grpc.Logger(options.Logger),
grpc.Flags(options.Flags...),
)
+76
View File
@@ -0,0 +1,76 @@
package http
import (
"context"
"github.com/micro/cli/v2"
"github.com/owncloud/ocis-accounts/pkg/config"
"github.com/owncloud/ocis-accounts/pkg/metrics"
"github.com/owncloud/ocis-pkg/v2/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Name string
Logger log.Logger
Context context.Context
Config *config.Config
Metrics *metrics.Metrics
Flags []cli.Flag
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Name provides a name for the service.
func Name(val string) Option {
return func(o *Options) {
o.Name = val
}
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
// Metrics provides a function to set the metrics option.
func Metrics(val *metrics.Metrics) Option {
return func(o *Options) {
o.Metrics = val
}
}
// Flags provides a function to set the flags option.
func Flags(val []cli.Flag) Option {
return func(o *Options) {
o.Flags = append(o.Flags, val...)
}
}
+71
View File
@@ -0,0 +1,71 @@
package http
import (
"github.com/go-chi/chi"
"github.com/owncloud/ocis-accounts/pkg/assets"
"github.com/owncloud/ocis-accounts/pkg/proto/v0"
svc "github.com/owncloud/ocis-accounts/pkg/service/v0"
"github.com/owncloud/ocis-accounts/pkg/version"
"github.com/owncloud/ocis-pkg/v2/middleware"
"github.com/owncloud/ocis-pkg/v2/service/http"
)
// Server initializes the http service and server.
func Server(opts ...Option) http.Service {
options := newOptions(opts...)
service := http.NewService(
http.Logger(options.Logger),
http.Name(options.Name),
http.Version(version.String),
http.Address(options.Config.HTTP.Addr),
http.Namespace(options.Config.HTTP.Namespace),
http.Context(options.Context),
http.Flags(options.Flags...),
)
handler, err := svc.New(svc.Logger(options.Logger), svc.Config(options.Config))
if err != nil {
options.Logger.Fatal().Err(err).Msg("could not initialize service handler")
}
mux := chi.NewMux()
mux.Use(middleware.RealIP)
mux.Use(middleware.RequestID)
mux.Use(middleware.Cache)
mux.Use(middleware.Cors)
mux.Use(middleware.Secure)
mux.Use(middleware.Version(
options.Name,
version.String,
))
mux.Use(middleware.Logger(
options.Logger,
))
mux.Use(middleware.Static(
options.Config.HTTP.Root,
assets.New(
assets.Logger(options.Logger),
assets.Config(options.Config),
),
))
mux.Route(options.Config.HTTP.Root, func(r chi.Router) {
proto.RegisterAccountsServiceWeb(r, handler)
proto.RegisterGroupsServiceWeb(r, handler)
})
service.Handle(
"/",
mux,
)
if err := service.Init(); err != nil {
panic(err)
}
return service
}