Skip to content

Commit

Permalink
feat(config): autoreload on config changes
Browse files Browse the repository at this point in the history
  • Loading branch information
SkalaNetworks committed Oct 16, 2023
1 parent 88da915 commit 15f7e62
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 22 deletions.
63 changes: 43 additions & 20 deletions cmd/gobgpd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"os/signal"
"runtime"
"syscall"
"time"

"github.com/coreos/go-systemd/v22/daemon"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
Expand All @@ -36,6 +37,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"golang.org/x/time/rate"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"

Expand All @@ -52,26 +54,27 @@ func main() {
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)

var opts struct {
ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"`
ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"`
LogLevel string `short:"l" long:"log-level" description:"specifying log level"`
LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
UseSyslog string `short:"s" long:"syslog" description:"use syslogd"`
Facility string `long:"syslog-facility" description:"specify syslog facility"`
DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"`
CPUs int `long:"cpus" description:"specify the number of CPUs to be used"`
GrpcHosts string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"`
GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"`
Dry bool `short:"d" long:"dry-run" description:"check configuration"`
PProfHost string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof and metrics" default:"localhost:6060"`
PProfDisable bool `long:"pprof-disable" description:"disable pprof profiling"`
MetricsPath string `long:"metrics-path" description:"specify path for prometheus metrics, empty value disables them" default:"/metrics"`
UseSdNotify bool `long:"sdnotify" description:"use sd_notify protocol"`
TLS bool `long:"tls" description:"enable TLS authentication for gRPC API"`
TLSCertFile string `long:"tls-cert-file" description:"The TLS cert file"`
TLSKeyFile string `long:"tls-key-file" description:"The TLS key file"`
TLSClientCAFile string `long:"tls-client-ca-file" description:"Optional TLS client CA file to authenticate clients against"`
Version bool `long:"version" description:"show version number"`
ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"`
ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"`
ConfigAutoReload bool `short:"a" long:"config-auto-reload" description:"activate config auto reload on changes"`
LogLevel string `short:"l" long:"log-level" description:"specifying log level"`
LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"`
UseSyslog string `short:"s" long:"syslog" description:"use syslogd"`
Facility string `long:"syslog-facility" description:"specify syslog facility"`
DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"`
CPUs int `long:"cpus" description:"specify the number of CPUs to be used"`
GrpcHosts string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"`
GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"`
Dry bool `short:"d" long:"dry-run" description:"check configuration"`
PProfHost string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof and metrics" default:"localhost:6060"`
PProfDisable bool `long:"pprof-disable" description:"disable pprof profiling"`
MetricsPath string `long:"metrics-path" description:"specify path for prometheus metrics, empty value disables them" default:"/metrics"`
UseSdNotify bool `long:"sdnotify" description:"use sd_notify protocol"`
TLS bool `long:"tls" description:"enable TLS authentication for gRPC API"`
TLSCertFile string `long:"tls-cert-file" description:"The TLS cert file"`
TLSKeyFile string `long:"tls-key-file" description:"The TLS key file"`
TLSClientCAFile string `long:"tls-client-ca-file" description:"Optional TLS client CA file to authenticate clients against"`
Version bool `long:"version" description:"show version number"`
}
_, err := flags.Parse(&opts)
if err != nil {
Expand Down Expand Up @@ -235,6 +238,26 @@ func main() {
}).Fatalf("Failed to apply initial configuration %s", opts.ConfigFile)
}

if opts.ConfigAutoReload {
logger.WithFields(logrus.Fields{
"Topic": "Config",
}).Info("Watching for config changes to trigger auto-reload")

// Writing to the config may trigger many events in quick successions
// To prevent abusive reloads, we ignore any event in a 100ms window
rateLimiter := rate.Sometimes{Interval: 100 * time.Millisecond}

config.WatchConfigFile(opts.ConfigFile, opts.ConfigType, func() {
rateLimiter.Do(func() {
logger.WithFields(logrus.Fields{
"Topic": "Config",
}).Info("Config changes detected, reloading configuration")

sigCh <- syscall.SIGHUP
})
})
}

for sig := range sigCh {
if sig != syscall.SIGHUP {
stopServer(bgpServer, opts.UseSdNotify)
Expand Down
5 changes: 4 additions & 1 deletion docs/sources/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ $ sudo -E gobgpd -f gobgpd.conf
If you use a configuration format other than `toml`, you must specify the format
by `-t` option.

equivalent yaml configuration.
Equivalent yaml configuration.

```yaml
global:
Expand All @@ -66,6 +66,9 @@ $ sudo -E gobgpd -t yaml -f gobgpd.yml
{"level":"info","msg":"Peer 10.0.255.2 is added","time":"2015-04-06T20:32:28+09:00"}
```

Sending the `SIGHUP` signal to `gobgpd` triggers a configuration reload.
The `-a` option enables the auto reloading of the configuration whenever a change is detected.

Let's show the information of all the peers.

```bash
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ require (
github.com/coreos/go-systemd/v22 v22.5.0
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13
github.com/eapache/channels v1.1.0
github.com/fsnotify/fsnotify v1.6.0
github.com/go-test/deep v1.1.0
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
Expand All @@ -20,6 +21,7 @@ require (
github.com/vishvananda/netlink v1.2.1-beta.2
golang.org/x/sys v0.6.0
golang.org/x/text v0.8.0
golang.org/x/time v0.3.0
google.golang.org/grpc v1.53.0
google.golang.org/protobuf v1.30.0
)
Expand All @@ -29,7 +31,6 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,10 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
Expand Down
13 changes: 13 additions & 0 deletions internal/pkg/config/serve.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"

"github.com/osrg/gobgp/v3/pkg/log"
Expand Down Expand Up @@ -42,6 +43,18 @@ func ReadConfigfile(path, format string) (*BgpConfigSet, error) {
return config, nil
}

func WatchConfigFile(path, format string, callBack func()) {
v := viper.New()
v.SetConfigFile(path)
v.SetConfigType(format)

v.OnConfigChange(func(e fsnotify.Event) {
callBack()
})

v.WatchConfig()
}

func ConfigSetToRoutingPolicy(c *BgpConfigSet) *RoutingPolicy {
return &RoutingPolicy{
DefinedSets: c.DefinedSets,
Expand Down
6 changes: 6 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ func ReadConfigFile(configFile, configType string) (*config.BgpConfigSet, error)
return config.ReadConfigfile(configFile, configType)
}

// WatchConfigFile calls the callback function anytime an update to the
// config file is detected.
func WatchConfigFile(configFile, configType string, callBack func()) {
config.WatchConfigFile(configFile, configType, callBack)
}

func marshalRouteTargets(l []string) ([]*apb.Any, error) {
rtList := make([]*apb.Any, 0, len(l))
for _, rtString := range l {
Expand Down

0 comments on commit 15f7e62

Please sign in to comment.