Skip to content

Commit

Permalink
Move common code to launcher.go
Browse files Browse the repository at this point in the history
  • Loading branch information
lschulz committed Dec 8, 2024
1 parent 65bebcd commit e94145d
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 263 deletions.
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
49 changes: 47 additions & 2 deletions private/app/launcher/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,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
140 changes: 140 additions & 0 deletions private/app/launcher/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,23 @@
package launcher

import (
"context"
"fmt"
"io"
"net"
"os"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"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/command"
"github.com/scionproto/scion/private/config"
libconfig "github.com/scionproto/scion/private/config"
"github.com/scionproto/scion/private/env"
)

Expand All @@ -38,6 +46,138 @@ const (
cfgConfigFile = "config"
)

// 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
// extract them from the config if that is the case. See the XxxConfig interfaces
// in this package for more information.
TOMLConfig libconfig.Config

// Samplers contains additional configuration samplers to be included
// under the sample subcommand. If empty, no additional samplers are
// listed.
//
// DEPRECATED. This field will be removed once Anapaya/scion#5000 is implemented.
Samplers []func(command.Pather) *cobra.Command

// ShortName is the short name of the application. If empty, the executable name is used.
// The ShortName could be, for example, "SCION Daemon" for the SCION Daemon.
ShortName string

// RequiredIPs should return the IPs that this application wants to listen
// on. The launcher will wait until those IPs can be listened on. The
// function is called after the configuration has been initialized. If this
// function is not set the launcher will immediately start the application
// without waiting for any IPs.
RequiredIPs func() ([]net.IP, error)

// Main is the custom logic of the application. If nil, no custom logic is executed
// (and only the setup/teardown harness runs). If Main returns an error, the
// Run method will return a non-zero exit code.
Main func(ctx context.Context) error

// ErrorWriter specifies where error output should be printed. If nil, os.Stderr is used.
ErrorWriter io.Writer

// config contains the Viper configuration KV store.
config *viper.Viper
}

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

func (a *ApplicationBase) loadConfig() error {
os.Setenv("TZ", "UTC")

// Load launcher configurations from the same config file as the custom
// application configuration.
a.config.SetConfigType("toml")
a.config.SetConfigFile(a.config.GetString(cfgConfigFile))
if err := a.config.ReadInConfig(); err != nil {
return serrors.Wrap("loading generic server config from file", err,
"file", a.config.GetString(cfgConfigFile))

}

if err := libconfig.LoadFile(a.config.GetString(cfgConfigFile), a.TOMLConfig); err != nil {
return serrors.Wrap("loading config from file", err,
"file", a.config.GetString(cfgConfigFile))

}
a.TOMLConfig.InitDefaults()
return nil
}

func (a *ApplicationBase) initLogging() error {
logEntriesTotal := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "lib_log_emitted_entries_total",
Help: "Total number of log entries emitted.",
},
[]string{"level"},
)
opt := log.WithEntriesCounter(log.EntriesCounter{
Debug: logEntriesTotal.With(prometheus.Labels{"level": "debug"}),
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()
if err != nil {
return serrors.Wrap("loading required IPs", err)
}
WaitForNetworkReady(ctx, ips)
}
if err := env.LogAppStarted(shortName, a.config.GetString(cfgGeneralID)); err != nil {
return err
}
defer env.LogAppStopped(shortName, a.config.GetString(cfgGeneralID))
defer log.HandlePanic()

exportBuildInfo()
prom.ExportElementID(a.config.GetString(cfgGeneralID))
if err := a.TOMLConfig.Validate(); err != nil {
return serrors.Wrap("validate config", err)
}

if a.Main == nil {
return nil
}
return a.Main(ctx)
}

func (a *ApplicationBase) getLogging() log.Config {
return log.Config{
Console: log.ConsoleConfig{
Level: a.config.GetString(cfgLogConsoleLevel),
Format: a.config.GetString(cfgLogConsoleFormat),
StacktraceLevel: a.config.GetString(cfgLogConsoleStacktraceLevel),
},
}
}

func (a *ApplicationBase) getErrorWriter() io.Writer {
if a.ErrorWriter != nil {
return a.ErrorWriter
}
return os.Stderr
}

// LoggingConfig is implemented by configurations that define logging behavior.
// If a application configuration does not implement this interface, then a
// default logging configuration is used.
Expand Down
Loading

0 comments on commit e94145d

Please sign in to comment.