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

run SCION as services on Windows #4657

Open
wants to merge 2 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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions control/cmd/control/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,13 @@ var globalCfg config.Config

func main() {
application := launcher.Application{
TOMLConfig: &globalCfg,
ShortName: "SCION Control Service",
// TODO(scrye): Deprecated additional sampler, remove once Anapaya/scion#5000 is in.
Samplers: []func(command.Pather) *cobra.Command{newSamplePolicy},
Main: realMain,
ApplicationBase: launcher.ApplicationBase{
TOMLConfig: &globalCfg,
ShortName: "SCION Control Service",
// TODO(scrye): Deprecated additional sampler, remove once Anapaya/scion#5000 is in.
Samplers: []func(command.Pather) *cobra.Command{newSamplePolicy},
Main: realMain,
},
}
application.Run()
}
Expand Down
8 changes: 5 additions & 3 deletions daemon/cmd/daemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ var globalCfg config.Config

func main() {
application := launcher.Application{
TOMLConfig: &globalCfg,
ShortName: "SCION Daemon",
Main: realMain,
ApplicationBase: launcher.ApplicationBase{
TOMLConfig: &globalCfg,
ShortName: "SCION Daemon",
Main: realMain,
},
}
application.Run()
}
Expand Down
10 changes: 6 additions & 4 deletions dispatcher/cmd/dispatcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ var globalCfg config.Config

func main() {
application := launcher.Application{
TOMLConfig: &globalCfg,
ShortName: "SCION Dispatcher",
RequiredIPs: requiredIPs,
Main: realMain,
ApplicationBase: launcher.ApplicationBase{
TOMLConfig: &globalCfg,
ShortName: "SCION Dispatcher",
RequiredIPs: requiredIPs,
Main: realMain,
},
}
application.Run()
}
Expand Down
8 changes: 5 additions & 3 deletions gateway/cmd/gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ var globalCfg config.Config

func main() {
application := launcher.Application{
TOMLConfig: &globalCfg,
ShortName: "SCION IP Gateway",
Main: realMain,
ApplicationBase: launcher.ApplicationBase{
TOMLConfig: &globalCfg,
ShortName: "SCION IP Gateway",
Main: realMain,
},
}
application.Run()
}
Expand Down
51 changes: 49 additions & 2 deletions private/app/launcher/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go_library(
name = "go_default_library",
srcs = [
"launcher.go",
"launcher_unix.go",
"launcher_windows.go",
"network.go",
],
importpath = "github.com/scionproto/scion/private/app/launcher",
Expand All @@ -12,15 +14,60 @@ go_library(
"//pkg/log:go_default_library",
"//pkg/private/prom:go_default_library",
"//pkg/private/serrors:go_default_library",
"//private/app:go_default_library",
"//private/app/command:go_default_library",
"//private/config:go_default_library",
"//private/env:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_spf13_cobra//:go_default_library",
"@com_github_spf13_viper//:go_default_library",
],
] + select({
"@io_bazel_rules_go//go/platform:aix": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:android": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:darwin": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:illumos": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:ios": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:js": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:plan9": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:solaris": [
"//private/app:go_default_library",
],
"@io_bazel_rules_go//go/platform:windows": [
"@org_golang_x_sys//windows/svc:go_default_library",
"@org_golang_x_sys//windows/svc/debug:go_default_library",
"@org_golang_x_sys//windows/svc/eventlog:go_default_library",
],
"//conditions:default": [],
}),
)

go_test(
Expand Down
84 changes: 14 additions & 70 deletions private/app/launcher/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ import (
"io"
"net"
"os"
"path/filepath"
"syscall"
"time"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
Expand All @@ -34,7 +31,6 @@ import (
"github.com/scionproto/scion/pkg/log"
"github.com/scionproto/scion/pkg/private/prom"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/private/app"
"github.com/scionproto/scion/private/app/command"
"github.com/scionproto/scion/private/config"
libconfig "github.com/scionproto/scion/private/config"
Expand All @@ -50,8 +46,8 @@ const (
cfgConfigFile = "config"
)

// Application models a SCION server application.
type Application struct {
// ApplicationBase provides common launcher functions for a SCION server application.
type ApplicationBase struct {
// TOMLConfig holds the Go data structure for the application-specific
// TOML configuration. The Application launcher will check if the TOMLConfig
// supports additional methods (e.g., custom logging or instance ID) and
Expand Down Expand Up @@ -89,73 +85,14 @@ type Application struct {
config *viper.Viper
}

// Run sets up the common SCION server harness, and then passes control to the Main
// function (if one exists).
//
// Run uses the following globals:
//
// os.Args
//
// Run will exit the application if it encounters a fatal error.
func (a *Application) Run() {
if err := a.run(); err != nil {
fmt.Fprintf(a.getErrorWriter(), "fatal error: %v\n", err)
os.Exit(1)
}
}

func (a *Application) run() error {
executable := filepath.Base(os.Args[0])
shortName := a.getShortName(executable)

cmd := newCommandTemplate(executable, shortName, a.TOMLConfig, a.Samplers...)
cmd.RunE = func(cmd *cobra.Command, args []string) error {
return a.executeCommand(cmd.Context(), shortName)
}
a.config = viper.New()
a.config.SetDefault(cfgLogConsoleLevel, log.DefaultConsoleLevel)
a.config.SetDefault(cfgLogConsoleFormat, "human")
a.config.SetDefault(cfgLogConsoleStacktraceLevel, log.DefaultStacktraceLevel)
a.config.SetDefault(cfgGeneralID, executable)
// The configuration file location is specified through command-line flags.
// Once the comand-line flags are parsed, we register the location of the
// config file with the viper config.
if err := a.config.BindPFlag(cfgConfigFile, cmd.Flags().Lookup(cfgConfigFile)); err != nil {
return err
}

// All servers accept SIGTERM to perform clean shutdown (for example, this
// is used behind the scenes by docker stop to cleanly shut down a container).
sigtermCtx := app.WithSignal(context.Background(), syscall.SIGTERM)
ctx, cancel := context.WithCancel(context.Background())

go func() {
defer log.HandlePanic()
<-sigtermCtx.Done()
log.Info("Received SIGTERM signal, exiting...")

// If the main goroutine shuts down everything in time, this won't get
// a chance to run.
time.AfterFunc(5*time.Second, func() {
defer log.HandlePanic()
panic("Main goroutine did not shut down in time (waited 5s). " +
"It's probably stuck. Forcing shutdown.")
})

cancel()
}()

return cmd.ExecuteContext(ctx)
}

func (a *Application) getShortName(executable string) string {
func (a *ApplicationBase) getShortName(executable string) string {
if a.ShortName != "" {
return a.ShortName
}
return executable
}

func (a *Application) executeCommand(ctx context.Context, shortName string) error {
func (a *ApplicationBase) loadConfig() error {
os.Setenv("TZ", "UTC")

// Load launcher configurations from the same config file as the custom
Expand All @@ -174,7 +111,10 @@ func (a *Application) executeCommand(ctx context.Context, shortName string) erro

}
a.TOMLConfig.InitDefaults()
return nil
}

func (a *ApplicationBase) initLogging() error {
logEntriesTotal := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "lib_log_emitted_entries_total",
Expand All @@ -187,10 +127,14 @@ func (a *Application) executeCommand(ctx context.Context, shortName string) erro
Info: logEntriesTotal.With(prometheus.Labels{"level": "info"}),
Error: logEntriesTotal.With(prometheus.Labels{"level": "error"}),
})

if err := log.Setup(a.getLogging(), opt); err != nil {
return serrors.Wrap("initialize logging", err)
}
return nil
}

func (a *ApplicationBase) executeCommand(ctx context.Context, shortName string) error {

defer log.Flush()
if a.RequiredIPs != nil {
ips, err := a.RequiredIPs()
Expand All @@ -217,7 +161,7 @@ func (a *Application) executeCommand(ctx context.Context, shortName string) erro
return a.Main(ctx)
}

func (a *Application) getLogging() log.Config {
func (a *ApplicationBase) getLogging() log.Config {
return log.Config{
Console: log.ConsoleConfig{
Level: a.config.GetString(cfgLogConsoleLevel),
Expand All @@ -227,7 +171,7 @@ func (a *Application) getLogging() log.Config {
}
}

func (a *Application) getErrorWriter() io.Writer {
func (a *ApplicationBase) getErrorWriter() io.Writer {
if a.ErrorWriter != nil {
return a.ErrorWriter
}
Expand Down
108 changes: 108 additions & 0 deletions private/app/launcher/launcher_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2020 Anapaya Systems
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !windows

package launcher

import (
"context"
"fmt"
"os"
"path/filepath"
"syscall"
"time"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/scionproto/scion/pkg/log"
"github.com/scionproto/scion/private/app"
)

// Application models a SCION server application.
type Application struct {
ApplicationBase
}

// Run sets up the common SCION server harness, and then passes control to the Main
// function (if one exists).
//
// Run uses the following globals:
//
// os.Args
//
// Run will exit the application if it encounters a fatal error.
func (a *Application) Run() {
if err := a.run(); err != nil {
fmt.Fprintf(a.getErrorWriter(), "fatal error: %v\n", err)
os.Exit(1)
}
}

func (a *Application) run() error {
executable := filepath.Base(os.Args[0])
shortName := a.getShortName(executable)

cmd := newCommandTemplate(executable, shortName, a.TOMLConfig, a.Samplers...)
cmd.RunE = func(cmd *cobra.Command, args []string) error {
return a.executeCommand(cmd.Context(), shortName)
}
a.config = viper.New()
a.config.SetDefault(cfgLogConsoleLevel, log.DefaultConsoleLevel)
a.config.SetDefault(cfgLogConsoleFormat, "human")
a.config.SetDefault(cfgLogConsoleStacktraceLevel, log.DefaultStacktraceLevel)
a.config.SetDefault(cfgGeneralID, executable)
// The configuration file location is specified through command-line flags.
// Once the comand-line flags are parsed, we register the location of the
// config file with the viper config.
if err := a.config.BindPFlag(cfgConfigFile, cmd.Flags().Lookup(cfgConfigFile)); err != nil {
return err
}

// All servers accept SIGTERM to perform clean shutdown (for example, this
// is used behind the scenes by docker stop to cleanly shut down a container).
sigtermCtx := app.WithSignal(context.Background(), syscall.SIGTERM)
ctx, cancel := context.WithCancel(context.Background())

go func() {
defer log.HandlePanic()
<-sigtermCtx.Done()
log.Info("Received SIGTERM signal, exiting...")

// If the main goroutine shuts down everything in time, this won't get
// a chance to run.
time.AfterFunc(5*time.Second, func() {
defer log.HandlePanic()
panic("Main goroutine did not shut down in time (waited 5s). " +
"It's probably stuck. Forcing shutdown.")
})

cancel()
}()

return cmd.ExecuteContext(ctx)
}

func (a *Application) executeCommand(ctx context.Context, shortName string) error {

if err := a.ApplicationBase.loadConfig(); err != nil {
return err
}
if err := a.ApplicationBase.initLogging(); err != nil {
return err
}

return a.ApplicationBase.executeCommand(ctx, shortName)
}
Loading