From d08e5efbce2c5795266f313ac075d4c37ec5ad7f Mon Sep 17 00:00:00 2001 From: Mikhail Bragin Date: Sun, 14 Nov 2021 19:41:17 +0100 Subject: [PATCH 1/3] fix: too many open files caused by agent not being closed (#154) * fix: too many open files caused by agent not being closed after unsuccessful attempts to start a peer connection (happens when no network available) * fix: minor refactor to consider signal status --- client/internal/connection.go | 10 ++++++++-- client/internal/engine.go | 7 ++++++- signal/client/client.go | 24 ++++++++++++++---------- signal/client/client_test.go | 2 +- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/client/internal/connection.go b/client/internal/connection.go index ed3dfc057..0a2662aed 100644 --- a/client/internal/connection.go +++ b/client/internal/connection.go @@ -138,12 +138,18 @@ func (conn *Connection) Open(timeout time.Duration) error { return !ok }, }) - conn.agent = a - if err != nil { return err } + conn.agent = a + defer func() { + err := conn.agent.Close() + if err != nil { + return + } + }() + err = conn.listenOnLocalCandidates() if err != nil { return err diff --git a/client/internal/engine.go b/client/internal/engine.go index 4145665e9..ce7421adf 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -148,6 +148,11 @@ func (e *Engine) initializePeer(peer Peer) { }, e.ctx) operation := func() error { + + if e.signal.GetStatus() != signal.StreamConnected { + return fmt.Errorf("not opening connection to peer because Signal is unavailable") + } + _, err := e.openPeerConnection(e.wgPort, e.config.WgPrivateKey, peer) e.peerMux.Lock() defer e.peerMux.Unlock() @@ -157,7 +162,7 @@ func (e *Engine) initializePeer(peer Peer) { } if err != nil { - log.Infof("retrying connection because of error: %s", err.Error()) + log.Debugf("retrying connection because of error: %s", err.Error()) return err } return nil diff --git a/signal/client/client.go b/signal/client/client.go index f49375cc4..005c1bac7 100644 --- a/signal/client/client.go +++ b/signal/client/client.go @@ -27,8 +27,8 @@ import ( // Status is the status of the client type Status string -const streamConnected Status = "streamConnected" -const streamDisconnected Status = "streamDisconnected" +const StreamConnected Status = "Connected" +const StreamDisconnected Status = "Disconnected" // Client Wraps the Signal Exchange Service gRpc client type Client struct { @@ -40,10 +40,14 @@ type Client struct { // connectedCh used to notify goroutines waiting for the connection to the Signal stream connectedCh chan struct{} mux sync.Mutex - // streamConnected indicates whether this client is streamConnected to the Signal stream + // StreamConnected indicates whether this client is StreamConnected to the Signal stream status Status } +func (c *Client) GetStatus() Status { + return c.status +} + // Close Closes underlying connections to the Signal Exchange func (c *Client) Close() error { return c.signalConn.Close() @@ -81,7 +85,7 @@ func NewClient(ctx context.Context, addr string, key wgtypes.Key, tlsEnabled boo signalConn: conn, key: key, mux: sync.Mutex{}, - status: streamDisconnected, + status: StreamDisconnected, }, nil } @@ -120,18 +124,18 @@ func (c *Client) Receive(msgHandler func(msg *proto.Message) error) error { // todo once the key rotation logic has been implemented, consider changing to some other identifier (received from management) stream, err := c.connect(c.key.PublicKey().String()) if err != nil { - log.Warnf("streamDisconnected from the Signal Exchange due to an error: %v", err) + log.Warnf("disconnected from the Signal Exchange due to an error: %v", err) return err } c.notifyStreamConnected() - log.Infof("streamConnected to the Signal Service stream") + log.Infof("connected to the Signal Service stream") // start receiving messages from the Signal stream (from other peers through signal) err = c.receive(stream, msgHandler) if err != nil { - log.Warnf("streamDisconnected from the Signal Exchange due to an error: %v", err) + log.Warnf("disconnected from the Signal Exchange due to an error: %v", err) backOff.Reset() return err } @@ -150,13 +154,13 @@ func (c *Client) Receive(msgHandler func(msg *proto.Message) error) error { func (c *Client) notifyStreamDisconnected() { c.mux.Lock() defer c.mux.Unlock() - c.status = streamDisconnected + c.status = StreamDisconnected } func (c *Client) notifyStreamConnected() { c.mux.Lock() defer c.mux.Unlock() - c.status = streamConnected + c.status = StreamConnected if c.connectedCh != nil { // there are goroutines waiting on this channel -> release them close(c.connectedCh) @@ -208,7 +212,7 @@ func (c *Client) ready() bool { // WaitStreamConnected waits until the client is connected to the Signal stream func (c *Client) WaitStreamConnected() { - if c.status == streamConnected { + if c.status == StreamConnected { return } diff --git a/signal/client/client_test.go b/signal/client/client_test.go index 55aeaf2c6..c2898e363 100644 --- a/signal/client/client_test.go +++ b/signal/client/client_test.go @@ -36,7 +36,7 @@ var _ = Describe("Client", func() { }) Describe("Exchanging messages", func() { - Context("between streamConnected peers", func() { + Context("between connected peers", func() { It("should be successful", func() { var msgReceived sync.WaitGroup From fcbf98058872dc438129ee62de40bc19f564b449 Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Sun, 14 Nov 2021 21:30:18 +0100 Subject: [PATCH 2/3] Stop service before uninstall (#158) --- client/installer.nsis | 1 + 1 file changed, 1 insertion(+) diff --git a/client/installer.nsis b/client/installer.nsis index 721742b7f..9064fa9a4 100644 --- a/client/installer.nsis +++ b/client/installer.nsis @@ -106,6 +106,7 @@ SectionEnd Section Uninstall ${INSTALL_TYPE} +Exec '"$INSTDIR\${MAIN_APP_EXE}" service stop' Exec '"$INSTDIR\${MAIN_APP_EXE}" service uninstall' # wait the service uninstall take unblock the executable Sleep 3000 From 7bf9793f85e16c72ae4ac8268cbf934e45ab7b80 Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Mon, 15 Nov 2021 09:11:50 +0100 Subject: [PATCH 3/3] Support environment vars (#155) * updage flag values from environment variables * add log and removing unused constants * removing unused code * Docker build client * fix indentation * Documentation with docker command * use docker volume --- .goreleaser.yaml | 58 ++++++++++++++++++++++++++++++++ README.md | 5 +++ client/Dockerfile | 4 +++ client/cmd/login.go | 7 ++-- client/cmd/root.go | 34 +++++++++++++++---- client/cmd/service.go | 3 -- client/cmd/service_controller.go | 14 +++++--- client/cmd/service_installer.go | 5 ++- client/cmd/up.go | 2 +- go.mod | 1 + 10 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 client/Dockerfile diff --git a/.goreleaser.yaml b/.goreleaser.yaml index f9fe15f1f..49faae1f4 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -85,6 +85,52 @@ nfpms: postinstall: "release_files/post_install.sh" preremove: "release_files/pre_remove.sh" dockers: + - image_templates: + - wiretrustee/wiretrustee:{{ .Version }}-amd64 + ids: + - wiretrustee + goarch: amd64 + use: buildx + dockerfile: client/Dockerfile + build_flag_templates: + - "--platform=linux/amd64" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title={{.ProjectName}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=maintainer=wiretrustee@wiretrustee.com" + - image_templates: + - wiretrustee/wiretrustee:{{ .Version }}-arm64v8 + ids: + - wiretrustee + goarch: arm64 + use: buildx + dockerfile: client/Dockerfile + build_flag_templates: + - "--platform=linux/arm64" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title={{.ProjectName}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=maintainer=wiretrustee@wiretrustee.com" + - image_templates: + - wiretrustee/wiretrustee:{{ .Version }}-arm + ids: + - wiretrustee + goarch: arm + goarm: 6 + use: buildx + dockerfile: client/Dockerfile + build_flag_templates: + - "--platform=linux/arm" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title={{.ProjectName}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - "--label=maintainer=wiretrustee@wiretrustee.com" - image_templates: - wiretrustee/signal:{{ .Version }}-amd64 ids: @@ -225,6 +271,18 @@ dockers: - "--label=org.opencontainers.image.version={{.Version}}" - "--label=maintainer=wiretrustee@wiretrustee.com" docker_manifests: + - name_template: wiretrustee/wiretrustee:{{ .Version }} + image_templates: + - wiretrustee/wiretrustee:{{ .Version }}-arm64v8 + - wiretrustee/wiretrustee:{{ .Version }}-arm + - wiretrustee/wiretrustee:{{ .Version }}-amd64 + + - name_template: wiretrustee/wiretrustee:latest + image_templates: + - wiretrustee/wiretrustee:{{ .Version }}-arm64v8 + - wiretrustee/wiretrustee:{{ .Version }}-arm + - wiretrustee/wiretrustee:{{ .Version }}-amd64 + - name_template: wiretrustee/signal:{{ .Version }} image_templates: - wiretrustee/signal:{{ .Version }}-arm64v8 diff --git a/README.md b/README.md index 21f67fdd3..910ba703b 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,11 @@ For **Windows** systems, start powershell as administrator and: ```shell wiretrustee up --setup-key ``` +For **Docker**, you can run with the following command: +```shell +docker run --network host --privileged --rm -d -e WT_SETUP_KEY= -v wiretrustee-client:/etc/wiretrustee wiretrustee/wiretrustee: +``` +> TAG > 0.3.0 version Alternatively, if you are hosting your own Management Service provide `--management-url` property pointing to your Management Service: ```shell diff --git a/client/Dockerfile b/client/Dockerfile new file mode 100644 index 000000000..45e36df09 --- /dev/null +++ b/client/Dockerfile @@ -0,0 +1,4 @@ +FROM gcr.io/distroless/base:debug +ENV WT_LOG_FILE=console +ENTRYPOINT [ "/go/bin/wiretrustee","up"] +COPY wiretrustee /go/bin/wiretrustee \ No newline at end of file diff --git a/client/cmd/login.go b/client/cmd/login.go index f3c27dce8..53759456b 100644 --- a/client/cmd/login.go +++ b/client/cmd/login.go @@ -18,12 +18,12 @@ import ( ) var ( - setupKey string - loginCmd = &cobra.Command{ Use: "login", Short: "login to the Wiretrustee Management Service (first run)", RunE: func(cmd *cobra.Command, args []string) error { + SetFlagsFromEnvVars() + err := util.InitLog(logLevel, logFile) if err != nil { log.Errorf("failed initializing log %v", err) @@ -151,6 +151,3 @@ func promptPeerSetupKey() (string, error) { return "", s.Err() } - -//func init() { -//} diff --git a/client/cmd/root.go b/client/cmd/root.go index 2c8368cb4..d1693818f 100644 --- a/client/cmd/root.go +++ b/client/cmd/root.go @@ -4,19 +4,15 @@ import ( "fmt" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/wiretrustee/wiretrustee/client/internal" "os" "os/signal" "runtime" + "strings" "syscall" ) -const ( - // ExitSetupFailed defines exit code - ExitSetupFailed = 1 - DefaultConfigPath = "" -) - var ( configPath string defaultConfigPath string @@ -24,6 +20,7 @@ var ( defaultLogFile string logFile string managementURL string + setupKey string rootCmd = &cobra.Command{ Use: "wiretrustee", Short: "", @@ -75,3 +72,28 @@ func SetupCloseHandler() { } }() } + +// SetFlagsFromEnvVars reads and updates flag values from environment variables with prefix WT_ +func SetFlagsFromEnvVars() { + flags := rootCmd.PersistentFlags() + flags.VisitAll(func(f *pflag.Flag) { + + envVar := FlagNameToEnvVar(f.Name) + + if value, present := os.LookupEnv(envVar); present { + err := flags.Set(f.Name, value) + if err != nil { + log.Infof("unable to configure flag %s using variable %s, err: %v", f.Name, envVar, err) + } + } + }) +} + +// FlagNameToEnvVar converts flag name to environment var name adding a prefix, +// replacing dashes and making all uppercase (e.g. setup-keys is converted to WT_SETUP_KEYS) +func FlagNameToEnvVar(f string) string { + prefix := "WT_" + parsed := strings.ReplaceAll(f, "-", "_") + upper := strings.ToUpper(parsed) + return prefix + upper +} diff --git a/client/cmd/service.go b/client/cmd/service.go index 2a60c31fe..0ec4199ed 100644 --- a/client/cmd/service.go +++ b/client/cmd/service.go @@ -34,6 +34,3 @@ var ( Short: "manages wiretrustee service", } ) - -func init() { -} diff --git a/client/cmd/service_controller.go b/client/cmd/service_controller.go index 82873fcab..b64da710c 100644 --- a/client/cmd/service_controller.go +++ b/client/cmd/service_controller.go @@ -8,7 +8,7 @@ import ( "time" ) -func (p *program) Start(s service.Service) error { +func (p *program) Start(service.Service) error { // Start should not block. Do the actual work async. log.Info("starting service") //nolint @@ -22,7 +22,7 @@ func (p *program) Start(s service.Service) error { return nil } -func (p *program) Stop(s service.Service) error { +func (p *program) Stop(service.Service) error { go func() { stopCh <- 1 }() @@ -41,6 +41,7 @@ var ( Use: "run", Short: "runs wiretrustee as service", Run: func(cmd *cobra.Command, args []string) { + SetFlagsFromEnvVars() err := util.InitLog(logLevel, logFile) if err != nil { @@ -75,6 +76,8 @@ var ( Use: "start", Short: "starts wiretrustee service", RunE: func(cmd *cobra.Command, args []string) error { + SetFlagsFromEnvVars() + err := util.InitLog(logLevel, logFile) if err != nil { log.Errorf("failed initializing log %v", err) @@ -101,6 +104,8 @@ var ( Use: "stop", Short: "stops wiretrustee service", Run: func(cmd *cobra.Command, args []string) { + SetFlagsFromEnvVars() + err := util.InitLog(logLevel, logFile) if err != nil { log.Errorf("failed initializing log %v", err) @@ -125,6 +130,8 @@ var ( Use: "restart", Short: "restarts wiretrustee service", Run: func(cmd *cobra.Command, args []string) { + SetFlagsFromEnvVars() + err := util.InitLog(logLevel, logFile) if err != nil { log.Errorf("failed initializing log %v", err) @@ -143,6 +150,3 @@ var ( }, } ) - -func init() { -} diff --git a/client/cmd/service_installer.go b/client/cmd/service_installer.go index 49331dd65..f5939a7d8 100644 --- a/client/cmd/service_installer.go +++ b/client/cmd/service_installer.go @@ -10,6 +10,7 @@ var ( Use: "install", Short: "installs wiretrustee service", RunE: func(cmd *cobra.Command, args []string) error { + SetFlagsFromEnvVars() svcConfig := newSVCConfig() @@ -49,6 +50,7 @@ var ( Use: "uninstall", Short: "uninstalls wiretrustee service from system", Run: func(cmd *cobra.Command, args []string) { + SetFlagsFromEnvVars() s, err := newSVC(&program{}, newSVCConfig()) if err != nil { @@ -65,6 +67,3 @@ var ( }, } ) - -func init() { -} diff --git a/client/cmd/up.go b/client/cmd/up.go index 228ec5d82..c63364d75 100644 --- a/client/cmd/up.go +++ b/client/cmd/up.go @@ -21,7 +21,7 @@ var ( Use: "up", Short: "install, login and start wiretrustee client", RunE: func(cmd *cobra.Command, args []string) error { - + SetFlagsFromEnvVars() err := loginCmd.RunE(cmd, args) if err != nil { return err diff --git a/go.mod b/go.mod index 76fc3f767..80333d82d 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/rs/cors v1.8.0 github.com/sirupsen/logrus v1.7.0 github.com/spf13/cobra v1.1.3 + github.com/spf13/pflag v1.0.5 github.com/vishvananda/netlink v1.1.0 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c