Skip to content

Commit

Permalink
concentratorconfig/etcdconfigweb: add cobra arg parsing
Browse files Browse the repository at this point in the history
Add cobra argument parsing to concentratorconfig and etcdconfigweb to
show the available configuration options to the user. Also allow
changing some hardcoded values/paths using command line arguments.
  • Loading branch information
Sven Püschel authored and pslldq committed Nov 18, 2024
1 parent 9269d9d commit 88dcf67
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 46 deletions.
81 changes: 56 additions & 25 deletions concentratorconfig/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ If an error occurs, it will print it and won't update any node.
Pass the simulate argument to only show the wireguard interface changes that would be applied.
When it is started this way, it exits after printing the changes.
The program expects a fixed Wireguard interface name (see [WG_DEVICENAME]) and
an etcd configuration file at a fixed location (see [github.com/ffbs/etcd-tools/ffbs.CreateEtcdConnection]).
The program expects by default a Wireguard interface named "wg-nodes"
and an etcd configuration file at "/etc/etcd-client.json".
These can be changed using command line flags.
*/
package main

Expand All @@ -24,12 +25,11 @@ import (

"github.com/ffbs/etcd-tools/ffbs"

"github.com/spf13/cobra"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

const WG_DEVICENAME = "wg-nodes"

func sortIPNet(s []net.IPNet) {
sort.Slice(s, func(i, j int) bool {
res := bytes.Compare(s[i].IP[:], s[j].IP[:])
Expand All @@ -41,17 +41,12 @@ func sortIPNet(s []net.IPNet) {
})
}

func calculateWGPeerUpdates(etcd *ffbs.EtcdHandler, wg *wgctrl.Client) ([]wgtypes.PeerConfig, error) {
func calculateWGPeerUpdates(etcd *ffbs.EtcdHandler, dev *wgtypes.Device) ([]wgtypes.PeerConfig, error) {
nodes, defNode, err := etcd.GetAllNodeInfo(context.Background())
if err != nil {
return nil, err
}

dev, err := wg.Device(WG_DEVICENAME)
if err != nil {
return nil, err
}

updates := make([]wgtypes.PeerConfig, 0, 10)

// remove and update existing nodes
Expand Down Expand Up @@ -139,18 +134,15 @@ func calculateWGPeerUpdates(etcd *ffbs.EtcdHandler, wg *wgctrl.Client) ([]wgtype
return updates, nil
}

func main() {
simulate := false
if len(os.Args) > 1 {
switch os.Args[1] {
case "simulate":
simulate = true
default:
log.Fatalln("unknown arguments. Currently only 'simulate' is supported")
}
}
type CLIConfig struct {
EtcdConfig string
UpdateInterval time.Duration
WGDeviceName string
Simulate bool
}

etcd, err := ffbs.CreateEtcdConnection()
func run(config *CLIConfig) {
etcd, err := ffbs.CreateEtcdConnection(config.EtcdConfig)
if err != nil {
log.Fatalln("Couldn't setup etcd connection:", err)
}
Expand All @@ -163,26 +155,65 @@ func main() {
for {
// misusing a loop to break at any moment and still run the sleep call
for {
updates, err := calculateWGPeerUpdates(etcd, wg)
dev, err := wg.Device(config.WGDeviceName)
if err != nil {
log.Println("Error getting Wireguard device", config.WGDeviceName, "and got error:", err)
break
}

updates, err := calculateWGPeerUpdates(etcd, dev)
if err != nil {
log.Println("Error trying to determine the node updates:", err)
break
}
if simulate {
if config.Simulate {
fmt.Printf("Peer updates: %v\n", updates)
return
}
if len(updates) == 0 {
break
}

if err := wg.ConfigureDevice(WG_DEVICENAME, wgtypes.Config{Peers: updates}); err != nil {
if err := wg.ConfigureDevice(config.WGDeviceName, wgtypes.Config{Peers: updates}); err != nil {
log.Println("Error trying to apply the node updates:", err)
break
}
log.Println("Updated", len(updates), "peers")
break
}
time.Sleep(60 * time.Second)
time.Sleep(config.UpdateInterval)
}
}

func main() {
var config CLIConfig

rootCmd := &cobra.Command{
Use: "concentratorconfig",
Short: "Configure the Wireguard interface based on the etcd KV configuration",
Run: func(cmd *cobra.Command, args []string) {
run(&config)
},
}

rootCmd.PersistentFlags().StringVarP(&config.EtcdConfig, "etcdconfig", "e", "/etc/etcd-client.json", "Path to the etcd client configuration file")
rootCmd.MarkFlagFilename("etcdconfig", "json")
rootCmd.PersistentFlags().DurationVarP(&config.UpdateInterval, "interval", "i", 60*time.Second, "Interval to update the wireguard configuration from the etcd store")
rootCmd.PersistentFlags().StringVarP(&config.WGDeviceName, "devicename", "d", "wg-nodes", "Wireguard device name to update the configuration")

simulateCmd := &cobra.Command{
Use: "simulate",
Short: "Simulate updating of the wireguard devices, but don't apply them",
Run: func(cmd *cobra.Command, args []string) {
config.Simulate = true
run(&config)
},
}

rootCmd.AddCommand(simulateCmd)

if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
58 changes: 42 additions & 16 deletions etcdconfigweb/main.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
/*
etcdconfigweb provides an http interface to query and register nodes from the etcd KV store.
By default it will listen on port 8080 on any interface. You can change this by passing an argument
like ":1234", which would configure to listen on port 1234 on any interface or "127.0.0.1:1234" to only listen
on the IPv4 local address "127.0.0.1" on port "1234".
It expects an etcd configuration file at a fixed location (see [github.com/ffbs/etcd-tools/ffbs.CreateEtcdConnection])
and a signify private key to sign the requests at "/etc/ffbs/node-config.sec"
By default it will listen on port 8080 on any interface.
It expects an etcd configuration file (by default at "/etc/etcd-client.json")
and a signify private key to sign the requests (by default at "/etc/ffbs/node-config.sec").
You can change these settings using command line options.
As it doesn't need any root capabilities, it should be considered to run this executable as a normal user.
Expand All @@ -17,25 +15,29 @@ The HTTP server supports two endpoints:
package main

import (
"fmt"
"log"
"net/http"
"os"

"github.com/ffbs/etcd-tools/ffbs"

"github.com/spf13/cobra"
)

func main() {
etcd, err := ffbs.CreateEtcdConnection()
type CLIConfig struct {
ListenAddr string
Key string
EtcdConfig string
}

func run(config *CLIConfig) {
etcd, err := ffbs.CreateEtcdConnection(config.EtcdConfig)
if err != nil {
log.Fatalln("Couldn't setup etcd connection: ", err)
}

servingAddr := ":8080"
if len(os.Args) > 1 {
servingAddr = os.Args[1]
}

signer, err := NewSignifySignerFromPrivateKeyFile("/etc/ffbs/node-config.sec")
signer, err := NewSignifySignerFromPrivateKeyFile(config.Key)
if err != nil {
log.Fatalln("Couldn't parse signify private key:", err)
}
Expand All @@ -45,6 +47,30 @@ func main() {
http.Handle("/config", &ConfigHandler{tracker: metrics, signer: signer, etcdHandler: etcd})
http.Handle("/etcd_status", metrics)

log.Println("Starting server on", servingAddr)
log.Fatal("Error running webserver:", http.ListenAndServe(servingAddr, nil))
log.Println("Starting server on", config.ListenAddr)
log.Fatal("Error running webserver:", http.ListenAndServe(config.ListenAddr, nil))
}

func main() {
var config CLIConfig

rootCmd := &cobra.Command{
Use: "etcdconfigweb",
Short: "Provide an HTTP interface to query and register nodes from the etcd KV store",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
run(&config)
},
}

rootCmd.PersistentFlags().StringVarP(&config.ListenAddr, "listen", "l", ":8080", "HTTP listening address to bind to")
rootCmd.PersistentFlags().StringVarP(&config.Key, "key", "k", "/etc/ffbs/node-config.sec", "Path to signify private key file to sign responses")
rootCmd.MarkFlagFilename("key", "sec")
rootCmd.PersistentFlags().StringVarP(&config.EtcdConfig, "etcdconfig", "e", "/etc/etcd-client.json", "Path to the etcd client configuration file")
rootCmd.MarkFlagFilename("etcdconfig", "json")

if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
13 changes: 10 additions & 3 deletions etcdutility/cmd_showoverrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,24 @@ import (
)

func init() {
var etcdConfig string

cmd := &cobra.Command{
Use: "showoverrides",
Short: "Shows all Pubkeys overriding a default value",
Run: showoverrides,
Run: func(cmd *cobra.Command, args []string) {
showoverrides(etcdConfig)
},
}

cmd.PersistentFlags().StringVarP(&etcdConfig, "etcdconfig", "e", "/etc/etcd-client.json", "Path to the etcd client configuration file")
cmd.MarkFlagFilename("etcdconfig", "json")

rootCmd.AddCommand(cmd)
}

func showoverrides(cmd *cobra.Command, args []string) {
etcd, err := ffbs.CreateEtcdConnection()
func showoverrides(etcdConfig string) {
etcd, err := ffbs.CreateEtcdConnection(etcdConfig)
if err != nil {
log.Fatalln("Couldn't setup etcd connection:", err)
}
Expand Down
4 changes: 2 additions & 2 deletions ffbs/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ type EtcdConfigFile struct {
// This function will only allow the configured CACert and
// ignores system root certificate authorities when connecting
// to the etcd server.
func CreateEtcdConnection() (*EtcdHandler, error) {
f, err := os.Open("/etc/etcd-client.json")
func CreateEtcdConnection(configFile string) (*EtcdHandler, error) {
f, err := os.Open(configFile)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 88dcf67

Please sign in to comment.