Add Settings window to Agent UI

Agent systray UI has been extended with
a setting window that allows configuring 
management URL, admin URL and 
supports pre-shared key.
While for the Netbird managed version 
the Settings are not necessary, it helps
to properly configure the self-hosted version.
This commit is contained in:
Givi Khojanashvili
2022-04-15 17:30:12 +02:00
committed by GitHub
parent 196207402d
commit 951e011a9c
25 changed files with 767 additions and 244 deletions
+56 -27
View File
@@ -2,12 +2,13 @@ package internal
import (
"fmt"
"net/url"
"os"
"github.com/netbirdio/netbird/iface"
"github.com/netbirdio/netbird/util"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"net/url"
"os"
)
var managementURLDefault *url.URL
@@ -17,7 +18,7 @@ func ManagementURLDefault() *url.URL {
}
func init() {
managementURL, err := parseManagementURL("https://api.wiretrustee.com:33073")
managementURL, err := parseURL("Management URL", "https://api.wiretrustee.com:33073")
if err != nil {
panic(err)
}
@@ -30,16 +31,17 @@ type Config struct {
PrivateKey string
PreSharedKey string
ManagementURL *url.URL
AdminURL *url.URL
WgIface string
IFaceBlackList []string
}
//createNewConfig creates a new config generating a new Wireguard key and saving to file
func createNewConfig(managementURL string, configPath string, preSharedKey string) (*Config, error) {
// createNewConfig creates a new config generating a new Wireguard key and saving to file
func createNewConfig(managementURL, adminURL, configPath, preSharedKey string) (*Config, error) {
wgKey := generateKey()
config := &Config{PrivateKey: wgKey, WgIface: iface.WgInterfaceDefault, IFaceBlackList: []string{}}
if managementURL != "" {
URL, err := parseManagementURL(managementURL)
URL, err := parseURL("Management URL", managementURL)
if err != nil {
return nil, err
}
@@ -62,55 +64,82 @@ func createNewConfig(managementURL string, configPath string, preSharedKey strin
return config, nil
}
func parseManagementURL(managementURL string) (*url.URL, error) {
func parseURL(serviceName, managementURL string) (*url.URL, error) {
parsedMgmtURL, err := url.ParseRequestURI(managementURL)
if err != nil {
log.Errorf("failed parsing management URL %s: [%s]", managementURL, err.Error())
return nil, err
}
if !(parsedMgmtURL.Scheme == "https" || parsedMgmtURL.Scheme == "http") {
return nil, fmt.Errorf("invalid Management Service URL provided %s. Supported format [http|https]://[host]:[port]", managementURL)
if parsedMgmtURL.Scheme != "https" && parsedMgmtURL.Scheme != "http" {
return nil, fmt.Errorf(
"invalid %s URL provided %s. Supported format [http|https]://[host]:[port]",
serviceName, managementURL)
}
return parsedMgmtURL, err
}
// ReadConfig reads existing config. In case provided managementURL is not empty overrides the read property
func ReadConfig(managementURL string, configPath string) (*Config, error) {
func ReadConfig(managementURL, adminURL, configPath string, preSharedKey *string) (*Config, error) {
config := &Config{}
_, err := util.ReadJson(configPath, config)
if err != nil {
if _, err := util.ReadJson(configPath, config); err != nil {
return nil, err
}
refresh := false
if managementURL != "" && config.ManagementURL.String() != managementURL {
URL, err := parseManagementURL(managementURL)
log.Infof("new Management URL provided, updated to %s (old value %s)",
managementURL, config.ManagementURL)
newURL, err := parseURL("Management URL", managementURL)
if err != nil {
return nil, err
}
config.ManagementURL = URL
// since we have new management URL, we need to update config file
err = util.WriteJson(configPath, config)
if err != nil {
return nil, err
}
log.Infof("new Management URL provided, updated to %s (old value %s)", managementURL, config.ManagementURL)
config.ManagementURL = newURL
refresh = true
}
return config, err
if adminURL != "" && (config.AdminURL == nil || config.AdminURL.String() != adminURL) {
log.Infof("new Admin Panel URL provided, updated to %s (old value %s)",
adminURL, config.AdminURL)
newURL, err := parseURL("Admin Panel URL", adminURL)
if err != nil {
return nil, err
}
config.AdminURL = newURL
refresh = true
}
if preSharedKey != nil && config.PreSharedKey != *preSharedKey {
log.Infof("new pre-shared key provided, updated to %s (old value %s)",
*preSharedKey, config.PreSharedKey)
config.PreSharedKey = *preSharedKey
refresh = true
}
if refresh {
// since we have new management URL, we need to update config file
if err := util.WriteJson(configPath, config); err != nil {
return nil, err
}
}
return config, nil
}
// GetConfig reads existing config or generates a new one
func GetConfig(managementURL string, configPath string, preSharedKey string) (*Config, error) {
func GetConfig(managementURL, adminURL, configPath, preSharedKey string) (*Config, error) {
if _, err := os.Stat(configPath); os.IsNotExist(err) {
log.Infof("generating new config %s", configPath)
return createNewConfig(managementURL, configPath, preSharedKey)
return createNewConfig(managementURL, adminURL, configPath, preSharedKey)
} else {
return ReadConfig(managementURL, configPath)
// don't overwrite pre-shared key if we receive asterisks from UI
pk := &preSharedKey
if preSharedKey == "**********" {
pk = nil
}
return ReadConfig(managementURL, adminURL, configPath, pk)
}
}
+8 -8
View File
@@ -2,24 +2,25 @@ package internal
import (
"errors"
"github.com/netbirdio/netbird/util"
"github.com/stretchr/testify/assert"
"os"
"path/filepath"
"testing"
"github.com/netbirdio/netbird/util"
"github.com/stretchr/testify/assert"
)
func TestReadConfig(t *testing.T) {
}
func TestGetConfig(t *testing.T) {
func TestGetConfig(t *testing.T) {
managementURL := "https://test.management.url:33071"
adminURL := "https://app.admin.url"
path := filepath.Join(t.TempDir(), "config.json")
preSharedKey := "preSharedKey"
// case 1: new config has to be generated
config, err := GetConfig(managementURL, path, preSharedKey)
config, err := GetConfig(managementURL, adminURL, path, preSharedKey)
if err != nil {
return
}
@@ -32,7 +33,7 @@ func TestGetConfig(t *testing.T) {
}
// case 2: existing config -> fetch it
config, err = GetConfig(managementURL, path, preSharedKey)
config, err = GetConfig(managementURL, adminURL, path, preSharedKey)
if err != nil {
return
}
@@ -42,7 +43,7 @@ func TestGetConfig(t *testing.T) {
// case 3: existing config, but new managementURL has been provided -> update config
newManagementURL := "https://test.newManagement.url:33071"
config, err = GetConfig(newManagementURL, path, preSharedKey)
config, err = GetConfig(newManagementURL, adminURL, path, preSharedKey)
if err != nil {
return
}
@@ -56,5 +57,4 @@ func TestGetConfig(t *testing.T) {
return
}
assert.Equal(t, readConf.(*Config).ManagementURL.String(), newManagementURL)
}
+19 -43
View File
@@ -2,9 +2,7 @@ package internal
import (
"context"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/google/uuid"
"github.com/netbirdio/netbird/client/system"
mgm "github.com/netbirdio/netbird/management/client"
@@ -16,16 +14,6 @@ import (
)
func Login(ctx context.Context, config *Config, setupKey string) error {
backOff := &backoff.ExponentialBackOff{
InitialInterval: time.Second,
RandomizationFactor: backoff.DefaultRandomizationFactor,
Multiplier: backoff.DefaultMultiplier,
MaxInterval: 2 * time.Second,
MaxElapsedTime: time.Second * 10,
Stop: backoff.Stop,
Clock: backoff.SystemClock,
}
// validate our peer's Wireguard PRIVATE key
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey)
if err != nil {
@@ -38,41 +26,29 @@ func Login(ctx context.Context, config *Config, setupKey string) error {
mgmTlsEnabled = true
}
loginOp := func() error {
log.Debugf("connecting to Management Service %s", config.ManagementURL.String())
mgmClient, err := mgm.NewClient(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled)
if err != nil {
log.Errorf("failed connecting to Management Service %s %v", config.ManagementURL.String(), err)
return err
}
log.Debugf("connected to management Service %s", config.ManagementURL.String())
log.Debugf("connecting to Management Service %s", config.ManagementURL.String())
mgmClient, err := mgm.NewClient(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled)
if err != nil {
log.Errorf("failed connecting to Management Service %s %v", config.ManagementURL.String(), err)
return err
}
log.Debugf("connected to management Service %s", config.ManagementURL.String())
serverKey, err := mgmClient.GetServerPublicKey()
if err != nil {
log.Errorf("failed while getting Management Service public key: %v", err)
return err
}
_, err = loginPeer(*serverKey, mgmClient, setupKey)
if err != nil {
log.Errorf("failed logging-in peer on Management Service : %v", err)
return err
}
err = mgmClient.Close()
if err != nil {
log.Errorf("failed closing Management Service client: %v", err)
return err
}
return nil
serverKey, err := mgmClient.GetServerPublicKey()
if err != nil {
log.Errorf("failed while getting Management Service public key: %v", err)
return err
}
err = backoff.RetryNotify(loginOp, backOff, func(err error, duration time.Duration) {
log.Warnf("retrying Login to the Management service in %v due to error %v", duration, err)
})
_, err = loginPeer(*serverKey, mgmClient, setupKey)
if err != nil {
log.Errorf("exiting login retry loop due to unrecoverable error: %v", err)
log.Errorf("failed logging-in peer on Management Service : %v", err)
return err
}
err = mgmClient.Close()
if err != nil {
log.Errorf("failed closing Management Service client: %v", err)
return err
}