-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split client app into cmd and daemon service (#239)
- Loading branch information
Showing
23 changed files
with
1,994 additions
and
580 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/wiretrustee/wiretrustee/client/proto" | ||
) | ||
|
||
var downCmd = &cobra.Command{ | ||
Use: "down", | ||
Short: "down wiretrustee connections", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
SetFlagsFromEnvVars() | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) | ||
defer cancel() | ||
|
||
conn, err := DialClientGRPCServer(ctx, daemonAddr) | ||
if err != nil { | ||
log.Errorf("failed to connect to service CLI interface %v", err) | ||
return err | ||
} | ||
defer conn.Close() | ||
|
||
daemonClient := proto.NewDaemonServiceClient(conn) | ||
|
||
if _, err := daemonClient.Down(ctx, &proto.DownRequest{}); err != nil { | ||
log.Errorf("call service down method: %v", err) | ||
return err | ||
} | ||
return nil | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,175 +1,66 @@ | ||
package cmd | ||
|
||
import ( | ||
"bufio" | ||
"context" | ||
"fmt" | ||
"os" | ||
"time" | ||
|
||
"github.com/cenkalti/backoff/v4" | ||
"github.com/google/uuid" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/wiretrustee/wiretrustee/client/internal" | ||
"github.com/wiretrustee/wiretrustee/client/system" | ||
mgm "github.com/wiretrustee/wiretrustee/management/client" | ||
mgmProto "github.com/wiretrustee/wiretrustee/management/proto" | ||
"github.com/wiretrustee/wiretrustee/util" | ||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"github.com/wiretrustee/wiretrustee/client/proto" | ||
) | ||
|
||
var ( | ||
loginCmd = &cobra.Command{ | ||
Use: "login", | ||
Short: "login to the Wiretrustee Management Service (first run)", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
SetFlagsFromEnvVars() | ||
|
||
var 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, | ||
} | ||
|
||
loginOp := func() error { | ||
|
||
err := util.InitLog(logLevel, logFile) | ||
if err != nil { | ||
log.Errorf("failed initializing log %v", err) | ||
return err | ||
} | ||
|
||
config, err := internal.GetConfig(managementURL, configPath, preSharedKey) | ||
if err != nil { | ||
log.Errorf("failed getting config %s %v", configPath, err) | ||
return err | ||
} | ||
|
||
//validate our peer's Wireguard PRIVATE key | ||
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey) | ||
if err != nil { | ||
log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) | ||
return err | ||
} | ||
|
||
ctx := context.Background() | ||
|
||
mgmTlsEnabled := false | ||
if config.ManagementURL.Scheme == "https" { | ||
mgmTlsEnabled = true | ||
} | ||
var loginCmd = &cobra.Command{ | ||
Use: "login", | ||
Short: "login to the Wiretrustee Management Service (first run)", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
SetFlagsFromEnvVars() | ||
ctx := internal.CtxInitState(context.Background()) | ||
|
||
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 | ||
// workaround to run without service | ||
if logFile == "console" { | ||
config, err := internal.GetConfig(managementURL, configPath, preSharedKey) | ||
if err != nil { | ||
log.Errorf("get config file: %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 = WithBackOff(func() error { | ||
return internal.Login(ctx, config, setupKey) | ||
}) | ||
if err != nil { | ||
log.Errorf("exiting login retry loop due to unrecoverable error: %v", err) | ||
return err | ||
log.Errorf("backoff cycle failed: %v", err) | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
) | ||
|
||
// loginPeer attempts to login to Management Service. If peer wasn't registered, tries the registration flow. | ||
func loginPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey string) (*mgmProto.LoginResponse, error) { | ||
|
||
loginResp, err := client.Login(serverPublicKey) | ||
if err != nil { | ||
if s, ok := status.FromError(err); ok && s.Code() == codes.PermissionDenied { | ||
log.Debugf("peer registration required") | ||
return registerPeer(serverPublicKey, client, setupKey) | ||
} else { | ||
return nil, err | ||
return err | ||
} | ||
} | ||
|
||
log.Info("peer has successfully logged-in to Management Service") | ||
|
||
return loginResp, nil | ||
} | ||
|
||
// registerPeer checks whether setupKey was provided via cmd line and if not then it prompts user to enter a key. | ||
// Otherwise tries to register with the provided setupKey via command line. | ||
func registerPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey string) (*mgmProto.LoginResponse, error) { | ||
if setupKey == "" { | ||
log.Error("setup key can't be empty") | ||
return fmt.Errorf("empty setup key") | ||
} | ||
|
||
var err error | ||
if setupKey == "" { | ||
setupKey, err = promptPeerSetupKey() | ||
conn, err := DialClientGRPCServer(ctx, daemonAddr) | ||
if err != nil { | ||
log.Errorf("failed getting setup key from user: %s", err) | ||
return nil, err | ||
log.Errorf("failed to connect to service CLI interface %v", err) | ||
return err | ||
} | ||
} | ||
|
||
validSetupKey, err := uuid.Parse(setupKey) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
log.Debugf("sending peer registration request to Management Service") | ||
info := system.GetInfo() | ||
loginResp, err := client.Register(serverPublicKey, validSetupKey.String(), info) | ||
if err != nil { | ||
log.Errorf("failed registering peer %v", err) | ||
return nil, err | ||
} | ||
defer conn.Close() | ||
|
||
log.Infof("peer has been successfully registered on Management Service") | ||
|
||
return loginResp, nil | ||
} | ||
|
||
// promptPeerSetupKey prompts user to enter Setup Key | ||
func promptPeerSetupKey() (string, error) { | ||
fmt.Print("Enter setup key: ") | ||
|
||
s := bufio.NewScanner(os.Stdin) | ||
for s.Scan() { | ||
input := s.Text() | ||
if input != "" { | ||
return input, nil | ||
request := proto.LoginRequest{ | ||
SetupKey: setupKey, | ||
PresharedKey: preSharedKey, | ||
ManagementUrl: managementURL, | ||
} | ||
fmt.Println("Specified key is empty, try again:") | ||
|
||
} | ||
|
||
return "", s.Err() | ||
client := proto.NewDaemonServiceClient(conn) | ||
err = WithBackOff(func() error { | ||
if _, err := client.Login(ctx, &request); err != nil { | ||
log.Errorf("try login: %v", err) | ||
} | ||
return err | ||
}) | ||
if err != nil { | ||
log.Errorf("backoff cycle failed: %v", err) | ||
} | ||
return err | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.