diff --git a/pkg/command/root.go b/pkg/command/root.go index 65a6792072..3c9211779e 100644 --- a/pkg/command/root.go +++ b/pkg/command/root.go @@ -5,28 +5,10 @@ import ( "strings" "github.com/micro/cli" - "github.com/micro/micro/api" - "github.com/micro/micro/bot" - "github.com/micro/micro/broker" - "github.com/micro/micro/debug" - "github.com/micro/micro/health" - "github.com/micro/micro/monitor" - "github.com/micro/micro/network" - "github.com/micro/micro/new" - "github.com/micro/micro/plugin/build" - "github.com/micro/micro/proxy" - "github.com/micro/micro/registry" - "github.com/micro/micro/router" - "github.com/micro/micro/runtime" - "github.com/micro/micro/server" - "github.com/micro/micro/service" - "github.com/micro/micro/store" - "github.com/micro/micro/token" - "github.com/micro/micro/tunnel" - "github.com/micro/micro/web" "github.com/owncloud/ocis-pkg/log" "github.com/owncloud/ocis/pkg/config" "github.com/owncloud/ocis/pkg/flagset" + "github.com/owncloud/ocis/pkg/micro/runtime" "github.com/owncloud/ocis/pkg/register" "github.com/owncloud/ocis/pkg/version" "github.com/spf13/viper" @@ -99,6 +81,8 @@ func Execute() error { }, } + // TODO(refs) fix this interface and make it play nice with cli.Command to reuse and skip + // doing runtime.AddRuntime(app) for _, fn := range register.Commands { app.Commands = append( app.Commands, @@ -106,8 +90,14 @@ func Execute() error { ) } - // adds micro runtime specific set of commands - addRuntime(app) + // add runtime commands to the binary + runtime.AddRuntime(app) + + // add the runtime.Run command to the binary + app.Commands = append( + app.Commands, + runtime.Command(app), + ) cli.HelpFlag = &cli.BoolFlag{ Name: "help,h", @@ -131,25 +121,3 @@ func NewLogger(cfg *config.Config) log.Logger { log.Color(cfg.Log.Color), ) } - -func addRuntime(app *cli.App) { - app.Commands = append(app.Commands, api.Commands()...) - app.Commands = append(app.Commands, bot.Commands()...) - app.Commands = append(app.Commands, broker.Commands()...) - app.Commands = append(app.Commands, health.Commands()...) - app.Commands = append(app.Commands, proxy.Commands()...) - app.Commands = append(app.Commands, monitor.Commands()...) - app.Commands = append(app.Commands, router.Commands()...) - app.Commands = append(app.Commands, tunnel.Commands()...) - app.Commands = append(app.Commands, network.Commands()...) - app.Commands = append(app.Commands, registry.Commands()...) - app.Commands = append(app.Commands, runtime.Commands()...) - app.Commands = append(app.Commands, debug.Commands()...) - app.Commands = append(app.Commands, server.Commands()...) - app.Commands = append(app.Commands, service.Commands()...) - app.Commands = append(app.Commands, store.Commands()...) - app.Commands = append(app.Commands, token.Commands()...) - app.Commands = append(app.Commands, new.Commands()...) - app.Commands = append(app.Commands, build.Commands()...) - app.Commands = append(app.Commands, web.Commands()...) -} diff --git a/pkg/command/server.go b/pkg/command/server.go index b1df23e6a5..81ea8499c6 100644 --- a/pkg/command/server.go +++ b/pkg/command/server.go @@ -1,10 +1,7 @@ package command import ( - "os" - "os/signal" "strings" - "syscall" "time" "contrib.go.opencensus.io/exporter/jaeger" @@ -12,43 +9,18 @@ import ( "contrib.go.opencensus.io/exporter/zipkin" "github.com/micro/cli" "github.com/micro/go-micro/config/cmd" - gorun "github.com/micro/go-micro/runtime" openzipkin "github.com/openzipkin/zipkin-go" zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http" - "github.com/owncloud/ocis-pkg/log" "github.com/owncloud/ocis/pkg/config" "github.com/owncloud/ocis/pkg/flagset" + "github.com/owncloud/ocis/pkg/micro/runtime" "go.opencensus.io/stats/view" "go.opencensus.io/trace" ) -// Services to start as part of the fullstack option -var services = []string{ - "network", // :8085 - "runtime", // :8088 - "registry", // :8000 - "broker", // :8001 - "store", // :8002 - "tunnel", // :8083 - "router", // :8084 - "monitor", // :???? - "debug", // :???? - "proxy", // :8081 - "api", // :8080 - "web", // :8082 - "bot", // :???? - - // extensions - "hello", - "phoenix", - "graph", - "ocs", - "webdav", -} - // Server is the entrypoint for the server command. func Server(cfg *config.Config) cli.Command { - app := cli.Command{ + return cli.Command{ Name: "server", Usage: "Start fullstack server", Category: "Fullstack", @@ -147,60 +119,19 @@ func Server(cfg *config.Config) cli.Command { Msg("Tracing is not enabled") } - mruntime := cmd.DefaultCmd.Options().Runtime + runtime := runtime.New( + runtime.Services(append(runtime.RuntimeServices, runtime.Extensions...)), + runtime.Logger(logger), + runtime.MicroRuntime(cmd.DefaultCmd.Options().Runtime), + ) // fork uses the micro runtime to fork go-micro services - forkServices(logger, mruntime) + runtime.Start() // trap blocks until a kill signal is sent - trap(logger, mruntime) + runtime.Trap() + return nil }, } - return app -} - -func trap(logger log.Logger, runtime *gorun.Runtime) { - shutdown := make(chan os.Signal, 1) - signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) - - logger.Info().Msg("Starting service runtime") - if err := (*runtime).Start(); err != nil { - os.Exit(1) - } - - logger.Info().Msgf("Service runtime started") - - // block until there is a value - for range shutdown { - logger.Info().Msg("shutdown signal received") - logger.Info().Msg("stopping service runtime") - close(shutdown) - } - - if err := (*runtime).Stop(); err != nil { - logger.Err(err) - } - - logger.Info().Msgf("Service runtime shutdown") - os.Exit(0) -} - -func forkServices(logger log.Logger, runtime *gorun.Runtime) { - env := os.Environ() - - for _, service := range services { - args := []gorun.CreateOption{ - // the binary calls itself with the micro service as a subcommand as first argument - gorun.WithCommand(os.Args[0], service), - gorun.WithEnv(env), - // and logs to STDOUT. Perhaps this can be overridden to use a log.Logger - gorun.WithOutput(os.Stdout), - } - - muService := &gorun.Service{Name: service} - if err := (*runtime).Create(muService, args...); err != nil { - logger.Error().Msgf("Failed to create runtime enviroment: %v", err) - } - } } diff --git a/pkg/micro/runtime/command.go b/pkg/micro/runtime/command.go new file mode 100644 index 0000000000..607c370dbb --- /dev/null +++ b/pkg/micro/runtime/command.go @@ -0,0 +1,31 @@ +package runtime + +import ( + "github.com/micro/cli" + "github.com/micro/go-micro/config/cmd" + "github.com/owncloud/ocis-pkg/log" +) + +// Command adds micro runtime commands to the cli app +func Command(app *cli.App) cli.Command { + command := cli.Command{ + Name: "micro-runtime", + Description: "starts the go-micro runtime and its services", + Category: "Base", + Action: func(c *cli.Context) error { + runtime := Runtime{ + Services: RuntimeServices, + R: cmd.DefaultCmd.Options().Runtime, + Logger: log.NewLogger(), + } + + { + runtime.Start() + runtime.Trap() + } + + return nil + }, + } + return command +} diff --git a/pkg/micro/runtime/options.go b/pkg/micro/runtime/options.go new file mode 100644 index 0000000000..8fd59499e3 --- /dev/null +++ b/pkg/micro/runtime/options.go @@ -0,0 +1,48 @@ +package runtime + +import ( + gorun "github.com/micro/go-micro/runtime" + "github.com/owncloud/ocis-pkg/log" +) + +// Options is a runtime option +type Options struct { + Services []string + Logger log.Logger + MicroRuntime *gorun.Runtime +} + +// Option undocummented +type Option func(o *Options) + +// newOptions initializes the available default options. +func newOptions(opts ...Option) Options { + opt := Options{} + + for _, o := range opts { + o(&opt) + } + + return opt +} + +// Services option +func Services(s []string) Option { + return func(o *Options) { + o.Services = append(o.Services, s...) + } +} + +// Logger option +func Logger(l log.Logger) Option { + return func(o *Options) { + o.Logger = l + } +} + +// MicroRuntime option +func MicroRuntime(rt *gorun.Runtime) Option { + return func(o *Options) { + o.MicroRuntime = rt + } +} diff --git a/pkg/micro/runtime/runtime.go b/pkg/micro/runtime/runtime.go new file mode 100644 index 0000000000..2fd9693089 --- /dev/null +++ b/pkg/micro/runtime/runtime.go @@ -0,0 +1,144 @@ +package runtime + +import ( + "os" + "os/signal" + "syscall" + + "github.com/micro/cli" + gorun "github.com/micro/go-micro/runtime" + "github.com/micro/micro/api" + "github.com/micro/micro/bot" + "github.com/micro/micro/broker" + "github.com/micro/micro/debug" + "github.com/micro/micro/health" + "github.com/micro/micro/monitor" + "github.com/micro/micro/network" + "github.com/micro/micro/new" + "github.com/micro/micro/plugin/build" + "github.com/micro/micro/proxy" + "github.com/micro/micro/registry" + "github.com/micro/micro/router" + "github.com/micro/micro/runtime" + "github.com/micro/micro/server" + "github.com/micro/micro/service" + "github.com/micro/micro/store" + "github.com/micro/micro/token" + "github.com/micro/micro/tunnel" + "github.com/micro/micro/web" + "github.com/owncloud/ocis-pkg/log" +) + +// RuntimeServices to start as part of the fullstack option +var RuntimeServices = []string{ + "network", // :8085 + "runtime", // :8088 + "registry", // :8000 + "broker", // :8001 + "store", // :8002 + "tunnel", // :8083 + "router", // :8084 + "monitor", // :???? + "debug", // :???? + "proxy", // :8081 + "api", // :8080 + "web", // :8082 + "bot", // :???? +} + +// Extensions are ocis extension services +var Extensions = []string{ + "hello", + "phoenix", + "graph", + "ocs", + "webdav", +} + +// Runtime is a micro' runtime +type Runtime struct { + Services []string + Logger log.Logger + R *gorun.Runtime +} + +// New creates a new ocis + micro runtime +func New(opts ...Option) Runtime { + options := newOptions(opts...) + + return Runtime{ + Services: options.Services, + Logger: options.Logger, + R: options.MicroRuntime, + } +} + +// Trap waits for a sigkill to stop the runtime +func (r *Runtime) Trap() { + shutdown := make(chan os.Signal, 1) + signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) + + r.Logger.Info().Msg("Starting service runtime") + if err := (*r.R).Start(); err != nil { + os.Exit(1) + } + + r.Logger.Info().Msgf("Service runtime started") + + // block until there is a value + for range shutdown { + r.Logger.Info().Msg("shutdown signal received") + r.Logger.Info().Msg("stopping service runtime") + close(shutdown) + } + + if err := (*r.R).Stop(); err != nil { + r.Logger.Err(err) + } + + r.Logger.Info().Msgf("Service runtime shutdown") + os.Exit(0) +} + +// Start starts preconfigured services +func (r *Runtime) Start() { + env := os.Environ() + + for _, service := range r.Services { + args := []gorun.CreateOption{ + // the binary calls itself with the micro service as a subcommand as first argument + gorun.WithCommand(os.Args[0], service), + gorun.WithEnv(env), + // and logs to STDOUT. Perhaps this can be overridden to use a log.Logger + gorun.WithOutput(os.Stdout), + } + + muService := &gorun.Service{Name: service} + if err := (*r.R).Create(muService, args...); err != nil { + r.Logger.Error().Msgf("Failed to create runtime enviroment: %v", err) + } + } +} + +// AddRuntime adds the micro subcommands to the cli app +func AddRuntime(app *cli.App) { + app.Commands = append(app.Commands, api.Commands()...) + app.Commands = append(app.Commands, bot.Commands()...) + app.Commands = append(app.Commands, broker.Commands()...) + app.Commands = append(app.Commands, health.Commands()...) + app.Commands = append(app.Commands, proxy.Commands()...) + app.Commands = append(app.Commands, monitor.Commands()...) + app.Commands = append(app.Commands, router.Commands()...) + app.Commands = append(app.Commands, tunnel.Commands()...) + app.Commands = append(app.Commands, network.Commands()...) + app.Commands = append(app.Commands, registry.Commands()...) + app.Commands = append(app.Commands, runtime.Commands()...) + app.Commands = append(app.Commands, debug.Commands()...) + app.Commands = append(app.Commands, server.Commands()...) + app.Commands = append(app.Commands, service.Commands()...) + app.Commands = append(app.Commands, store.Commands()...) + app.Commands = append(app.Commands, token.Commands()...) + app.Commands = append(app.Commands, new.Commands()...) + app.Commands = append(app.Commands, build.Commands()...) + app.Commands = append(app.Commands, web.Commands()...) +}